【问题标题】:Including common property decorators包括常见的属性装饰器
【发布时间】:2021-02-25 02:21:49
【问题描述】:

我正在寻找一种将通用属性装饰器添加到类的速记。

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

我正在寻找“打包”颜色属性的最简单方法,以便我可以将其分配给 Dog 和 Cat,而不是 InvisibleMan。像这样的东西(虽然实际上会有大约 8 个这样的属性和大约 15 个这样的类)

    class Dog(Animal):

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

【问题讨论】:

  • 为什么不直接在Animal类中添加呢?

标签: python-3.x oop inheritance decorator


【解决方案1】:

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

简而言之,描述符可以让您对属性存储进行细粒度控制。 (事实上​​,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'

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

【讨论】:

    【解决方案2】:

    你有一些选择。

    首先,多重继承:

    # 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 将覆盖 invisible man 中的 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 
    

    然后你可以有一种方法来设置隐身和关闭,并使所有猫默认不可见。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-09-05
      • 1970-01-01
      • 2019-07-29
      • 1970-01-01
      • 2020-06-20
      • 2011-05-30
      • 2015-10-09
      • 2017-03-15
      相关资源
      最近更新 更多