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

时间:2018-06-22 21:13:43

标签: python python-3.x decorator python-decorators flyweight-pattern

我有一个使精灵轻量化的类,并且我正在使用装饰器来调用此类。这是一些代码:

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'

我应该重塑我的flyweight实现,还是可以解决这个问题?

2 个答案:

答案 0 :(得分:1)

装饰后,包装对象的名称会自动指向装饰器的返回结果。在这种情况下,Sprite现在存储flyweight的实例,而该实例依次包含一个属性,该属性存储原始包装类Sprite的实例。例如,在声明后打印Sprite会得到:<__main__.flyweight object at 0x102373080>。但是,可以从staticmethod调用from_colour _cls

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

答案 1 :(得分:0)

flyweight装饰器确实应该通过所有构造函数传递给基础类,包括@classmethod@staticmethod备用构造函数。实际上,更一般地说,类装饰器确实应该保留包装的类的整个公共接口。

并且,尽管我们可以轻松地修改flyweight以专门通过Sprite接口的其余部分,在这种情况下,该接口只是from_colour方法,但这对于一个不太琐碎的课程,或一个不断变化的课程。真的,制作仅适用于单个类的装饰器有什么意义?

因此,我们将其更改为:

  • 获取任何构造函数签名。理想情况下,我们希望使它可以在签名的哪一部分算作密钥 1 上进行配置,但是为了避免事情变得过于复杂,我们将其固定为第一个参数。

  • 通过类的整个公共接口,而不仅仅是其__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。对于类构造缓存,它应该同样有意义。