包括常见的 属性 装饰器

Including common property decorators

我正在寻找一个 shorthand 来为 类 添加常见的 属性 装饰器。

class Animal:
    def __init__(self):
        self._attributes = {}
    

class Dog(Animal):

    @property
    def color(self):
        return super()._attributes.get('color', None)

    @color.setter
    def color(self, value):
        if value is not None:
            super()._attributes['color'] = value
        else:
            super()._attributes.pop('color', None)


class Cat(Animal):

    @property
    def color(self):
        return super()._attributes.get('color', None)

    @color.setter
    def color(self, value):
        if value is not None:
            super()._attributes['color'] = value
        else:
            super()._attributes.pop('color', None)


class InvisibleMan(Animal):
    pass

我正在寻找最简单的方法来“打包”颜色 属性,这样我就可以将它分配给狗和猫,而不是 InvisibleMan。像这样的东西(尽管实际上会有 ~8 个这样的属性和 ~15 个这样的 类)

    class Dog(Animal):

        def __init__(self):
            super().__init__()
            includeColorProperty(self)

你有关于选项。

首先,多重继承:

# this is the best way to do things if lots of stuff is invisible 

class HasColor:
   # getter and setter go here

class Dog(Animal,HasColor):
   ...

# This is probably the best one way to do things, if not many things are invisible 

class Invisible:
    @property 
    def color(self):
        raise AttributeError("very meaningful message")


class InvisibleMan(Invisible,Animal):  # THE ORDER HERE MATTERS!!
    etc

选项 2 将覆盖隐形人中的 getter 和 setter:

class Dog(Animal):
   ...

class InvisibleMan(Animal): 
    @property 
    def color(self):
        raise AttributeError("very meaningful message")

奖金选项:

如果你想在一个实例上打开和关闭隐形,那么你想做其他事情。我不确定你是否想要这个但是:

class Animal:
   cloaking_on = False 
   
   @property 
   def color(self):
      if self.cloaking_on:
          raise AttributeError(etc)
      etc 

然后你就可以有办法打开和关闭隐形,让所有的猫默认不可见。

您是否考虑过描述符而不是装饰器?

简而言之,描述符使您可以对属性存储进行细粒度控制。 (事实上​​,property 装饰器在幕后构建了一个描述符!)这里有一些 Python docs 可能会有帮助。

无论如何,坚持你的模式,操纵 _attributes 的描述符看起来像这样:

class Color:

    def __get__(self, obj, objtype=None):
        return obj._attributes.get('color')
        
    def __set__(self, obj, value):
        if value is None:
            obj._attributes.pop('color', None)
        else:
            obj._attributes['color'] = value

其中 obj 是对 Dog 实例等的引用

(请注意 __get____set__ 方法分别匹配您的 getter 和 setter。)

然后,像这样将描述符插入您的 类:

class Animal:
    def __init__(self):
        self._attributes = {}
    

class Dog(Animal):

    color = Color()


class Cat(Animal):

    color = Color()


class InvisibleMan(Animal):
    pass

您可以在这个例子中看到您正在寻找的行为被保留:实例保持它们自己的 _attributes,并且 InvisibleMan 没有 color:

>>> d1, d2 = Dog(), Dog()
>>> d1.color = 'blue'
>>> d1.color, d2.color
('blue', None)
>>>
>>>
>>> x = InvisibleMan()
>>> x.color
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'InvisibleMan' object has no attribute 'color'

就我个人而言,当涉及许多属性时,我也发现这更容易阅读,正如您提到的那样,在您的情况下是正确的。想知道给定类型有哪些属性?它们列在顶部,不足为奇。