Python-可以将相同的属性逻辑应用于多个属性吗?

时间:2019-03-01 21:58:59

标签: python python-3.x properties decorator

是否可以将相同的属性逻辑应用于类中的一组属性?例如,我想将相同的@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

2 个答案:

答案 0 :(得分: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 < 0)。另请注意,您可能不希望使用双下划线名称处理(并不表示私有),因此我使用了常规单下划线来表示不属于公共API的变量。使用双下划线的名称处理会使这里的事情复杂化。

答案 1 :(得分:0)

您可以覆盖__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