将静态方法与享元装饰器一起使用时出错
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 构造缓存应该同样有意义。
我有一个 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 构造缓存应该同样有意义。