将静态方法与享元装饰器一起使用时出错

Error when using staticmethod with flyweight decorator

我有一个 class 用于制作轻量级精灵,我正在使用一个装饰器来调用它 class。这是一些代码:

class flyweight:
    def __init__(self, cls):
        self._cls = cls
        self.__instances = dict()

    def __call__(self, title):
        return self.__instances.setdefault((title), self._cls(title))

在这个问题中,我将简化代码以显示相关内容。

@flyweight
class Sprite:
    def __init__(self, title, surf=None):
        self.title = title
        self.surf = surf if surf is not None else pygame.image.load('Images/Sprites/'+title+'.png').convert_alpha()
        self.w, self.h = self.surf.get_size()

    @staticmethod
    def from_colour(colour, size=(40,40)):
        surf = pygame.Surface(size).convert(); surf.fill(colour)
        return Sprite(colour, surf)

red = Sprite.from_colour((125,0,0))

但这给了我错误:

AttributeError: 'flyweight' object has no attribute 'from_colour'

我应该改造我的享元实现还是有什么办法可以解决这个问题?

装饰后,被包装对象的名称自动指向装饰器的返回结果。在这种情况下,Sprite 现在存储 flyweight 的一个实例,它又包含一个存储原始包装 class Sprite 实例的属性。例如,在声明后打印 Sprite 给出:<__main__.flyweight object at 0x102373080>。但是,可以从 _cls:

调用 staticmethod from_colour
red = Sprite._cls.from_colour((125,0,0))

flyweight 装饰器确实应该将所有构造函数传递给底层 class,包括 @classmethod@staticmethod 备用构造函数。事实上,更一般地说,class 装饰器确实应该保留包装的 class 的整个 public 接口。

而且,虽然我们可以很容易地修改 flyweight 以专门通过 Sprite 接口的其余部分,在这种情况下只是那个 from_colour 方法,那将是一个为不那么琐碎的 class 或不断变化的 class 带来痛苦。真的,制作一个只适用于单个 class 的装饰器有什么意义?

所以,让我们将其更改为:

  • 取任意构造函数签名。理想情况下,我们希望根据签名的哪一部分作为密钥进行配置,1 但为了避免事情变得太复杂,让我们将其固定为第一个参数。

  • 通过 class 的整个 public 接口,而不仅仅是它的 __call__ 接口。

所以:

class flyweight:
    def __init__(self, cls):
        self._cls = cls
        self.__instances = dict()

    def __call__(self, key, *args, **kw):
        return self.__instances.setdefault(key, self._cls(key, *args, **kw))

    def __getattr__(self, name):
        if not name.startswith('_'):
            return getattr(self._cls, name)

1.我使用过的其他一些库对此有一个很好的功能备忘录缓存设计。大概cachetools。它对 class 构造缓存应该同样有意义。