python Property属性使用

特性property

当有对属性赋值进行操作的需求时,可以使用property。这可以将一个属性的赋值、获取、删除拆分为3个动作,分别进行不同的实现。

class F1:
    @property                         #获取number属性的方法
    def number(self):
        return self._number

    @number.setter					#设置number属性的方法,这里是在设置时对数值减1
    def number(self, number):
        self._number = number-1

    @number.deleter					#删除number属性的方法,这里是在删除时个别更改为None
    def number(self):
        self._number = None

在实现上可以分为两种,主动计算和延迟计算。 在每次更改时(setter和deleter)计算属性值为主动,在get时计算为延迟。这个后面在细说。

使用property在使用上和正常的属性操作没有区别,不过会实现你自己的逻辑。

>> f = F1()
>> f.number = 10
>> f.number
   9

特殊方法

实际上property内部是用这些特殊方法实现的。这些特殊方法正常来说是对当前类中所有属性生效的,而property只是对指定的属性

_setattr_

用于创建属性和赋值

_getattr_

用于获取属性值。如果未被定义会抛出AttributeError

_delattr_

用于删除属性

_dir_

返回属性名称列表。注意,方法也是属性,所以返回值中时包含方法名的

主动计算属性

当一个属性更改时,自动计算其他属性值

使用property setter

缺点是如果多个属性需要主动计算,那么需要多个setter

class F1:
    @property                         #获取number属性的方法
    def number(self):
        return self._number

    @number.setter					#设置number属性的方法
    def number(self, number):
        self._number = number-1		#在属性进行更改时进行计算

    @number.deleter					#删除number属性的方法
    def number(self):
        self._number = None

重写字典

class F1(dict):
    def __init__(self,*args,**kwargs):
        super().__init__(*args,**kwargs)
        self._solve()
	
    # 在设置属性的同时调用计算函数
    def __setattr__(self, key, value):   
        self[key] = value
        self._solve()
	
    # 修改get方法,支持点语法
    def __getattr__(self, item):
        return self.get(item,None)
	
    # 属性名称的列表只返回字典中的键,即实例的属性
    def __dir__(self):
        return list(self.keys())
	
    # 如果有两个值,那么自动计算第三个值
    def _solve(self):
        if self.sum is not None and self.first is not None:
            self['second'] = self.sum - self.first
        elif self.sum is not None and self.second is not None:
            self['first'] = self.sum - self.second
        elif self.second is not None and self.first is not None:
            self['sum'] = self.first + self.second
>> f = F1()
>> f.second = 10
>> f.first = 9
>> print(f)
>> {'second': 10, 'first': 9, 'sum': 19}
>> f.first = 7
>> print(f)
>> {'second': 12, 'first': 7, 'sum': 19}
# 因为判断顺序的原因,在第一次自动计算之后(即三个属性都有值),再次对second赋值无法触发计算
# 因为 sum 和first 都有值, 无法到达第二个elif判断

如果是针对单个属性,那么使用property。而重写字典的形式,一般来说需要搭配限制属性添加来使用。