pygame-community / pygame-ce

🐍🎮 pygame - Community Edition is a FOSS Python library for multimedia applications (like games). Built on top of the excellent SDL library.
https://pyga.me
773 stars 120 forks source link

Adding the __getattr__ method to DirtySprite may lead to infinite recursion #2790

Closed LondonClass closed 2 months ago

LondonClass commented 3 months ago

Many ways can lead to infinite recursion.

1.Just print self.

import pygame

class MySprite(pygame.sprite.DirtySprite):
    def __init__(self, *args):
        super().__init__()

    def __getattr__(self, name):
        print(self)

sprite = MySprite()

2.Using an undefined variable

import pygame

class MySprite(pygame.sprite.DirtySprite):
    def __init__(self, *args):
        super().__init__()
        self.a = 0

    def __getattr__(self, name):
        print(self.a)

sprite = MySprite()

If I want to implement this function:

import pygame

class MySprite(pygame.sprite.DirtySprite):
    def __init__(self, *args):
        super().__init__()
        self.image = pygame.Surface((100, 100))

    def __getattr__(self, name):
        return getattr(self.image, name)

sprite = MySprite()

Method 1:

import pygame

class MySprite(pygame.sprite.DirtySprite):
    def __init__(self, *args):
        self.intialized = False
        super().__init__()
        self.intialized = True
        self.image = pygame.Surface((100, 100))

    def __getattr__(self, name):
        if self.intialized:
            return getattr(self.image, name)

sprite = MySprite()

Method 2:

import pygame

class MySprite(pygame.sprite.DirtySprite):
    def __init__(self, *args):
        super().__init__()
        self.image = pygame.Surface((100, 100))

    def __getattr__(self, name):
        if name == "_Sprite__image":
            return
        return getattr(self.image, name)

sprite = MySprite()

Method 3:

import pygame

class MySprite(pygame.sprite.DirtySprite):
    def __init__(self, *args):
        self.image = None
        super().__init__()
        self.image = pygame.Surface((100, 100))

    def __getattr__(self, name):
        return getattr(self.image, name)

sprite = MySprite()
Starbuck5 commented 2 months ago

I don't think this has anything to do with the sprite class, it's just your use of __getattr__.

class Test:
    def __init__(self, val):
        self.val = val

    def __getattr__(self, name):
        return self.x

a = Test(2)
print(a.x)
Traceback (most recent call last):
  File "C:\Users\charl\Desktop\test7.py", line 10, in <module>
    print(a.x)
  File "C:\Users\charl\Desktop\test7.py", line 6, in __getattr__
    return self.x
  File "C:\Users\charl\Desktop\test7.py", line 6, in __getattr__
    return self.x
  File "C:\Users\charl\Desktop\test7.py", line 6, in __getattr__
    return self.x
  [Previous line repeated 996 more times]
RecursionError: maximum recursion depth exceeded