【问题标题】:Python - Can same property logic be applied to multiple attributes?Python - 可以将相同的属性逻辑应用于多个属性吗?
【发布时间】:2019-07-23 23:19:28
【问题描述】:

有没有办法将相同的属性逻辑应用于类中的一组属性?例如,我想将相同的@attr1.setter 装饰器应用于attr2attr3attr4,而不必为每个属性定义属性。

class Sample:
    def __init__(self):
        self.attr1 = None
        self.attr2 = None
        self.attr3 = None
        self.attr4 = None

    @property
    def attr1(self):
        return self.__attr1

    @attr1.setter
    def attr1(self, val):
        if val < 0:
            self.__attr1 = 0
        else:
            self.__attr1 = val

【问题讨论】:

    标签: python python-3.x properties decorator


    【解决方案1】:

    只需为此创建您自己的描述符:

    class MyDescriptor:
        def __set_name__(self, owner, name):
            self.name = f'_{name}'
        def __get__(self, instance, owner):
            return getattr(instance, self.name)
        def __set__(self, instance, val):
            if val is None:
                setattr(instance, self.name, None)
            elif val < 0:
                setattr(instance, self.name, 0)
            else:
                setattr(instance, self.name, val)
    
    class Sample:
        attr1 = MyDescriptor()
        attr2 = MyDescriptor()
        attr3 = MyDescriptor()
        attr4 = MyDescriptor()
        def __init__(self):
            self.attr1 = None
            self.attr2 = None
            self.attr3 = None
            self.attr4 = None
    

    现在,行动起来:

    In [3]: s = Sample()
    
    In [4]: s.attr1 = -99
    
    In [5]: s.attr1
    Out[5]: 0
    
    In [6]: s.attr2
    
    In [7]: s.attr2 = 10
    
    In [8]: s.attr2
    Out[8]: 10
    
    In [9]: s.attr2 = -1
    
    In [10]: s.attr2
    Out[10]: 0
    

    查看Descriptor HOWTO 和一些更相关的documentation

    注意,我在你的设置器逻辑中加入了None 的可能性(你的代码会在初始化实例时引发TypeError,因为设置器检查是否None &lt; 0)。另请注意,您可能不想使用双下划线名称修饰(这并不意味着私有),所以我使用 常规 单下划线表示不属于公共 api 的变量。在这里使用双下划线名称修饰会使事情变得复杂。

    【讨论】:

    • 如果我将 attr1/2/3/4 定义为类属性,它们不会在类实例之间共享吗?即attr1 = MyDescriptor()
    • @tyleax 正是property 正在做的事情。也就是说,属性对象属于。所以@property def blah().... 等价于def blah() ... blah = property(blah)。描述符(property 只是一个方便的描述符)始终属于该类。
    【解决方案2】:

    您可以覆盖 __getattr____setattr__ 以按照您希望的方式运行。这样您就不需要定义任何私有变量,也不需要初始化任何成员变量。

    class Sample:
        def __getattr__(self, attr):
            return self.__dict__.get(attr)
    
        def __setattr__(self, attr, val):
            if val is not None and val < 0:
                self.__dict__[attr] = 0
            else:
                self.__dict__[attr] = val
    
    s = Sample()
    
    print(s.attr1) # None
    s.attr1 = 10
    print(s.attr1) # 10
    s.attr1 = -10
    print(s.attr1) # 0
    s.attr1 = None
    print(s.attr1) # None
    

    【讨论】:

      猜你喜欢
      • 2018-07-02
      • 1970-01-01
      • 2015-03-15
      • 2011-05-27
      • 2015-09-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-03
      • 1970-01-01
      相关资源
      最近更新 更多