Python 中的属性方法@property 介绍

1. 类属性和实例属性

Python中类和实例都是对象, 可以在定义时或者通过 . 语法设置和读取属性内容. 

In [1]: class Demo:
   ...:     cls_name = "Demo"
   ...:     def __init__(self, name):
   ...:         self.name = name
In [2]: demo = Demo('demo')

In [3]: demo.name
Out[3]: 'demo'
In [4]: demo.cls_name
Out[4]: 'Demo'
In [5]: Demo.cls_name
Out[5]: 'Demo'

In [6]: Demo.cls_name = 'New Class Name'
In [7]: demo.cls_name
Out[7]: 'New Class Name'

In [8]: demo.cls_name = 'Custom Name'
In [9]: demo.cls_name
Out[9]: 'Custom Name'

上面的代码示例, 先定义了一个Demo类, 包含一个类属性cls_name, __init__方法中初始化实例的时候, 定义了实例属性name. 

demo是Demo类的一个实例, 可以看到通过demo可以访问实例属性name='demo', 当在实例中获取不到一个属性的值的时候, 会尝试去父类中获取, 类似"子债父偿"的概念, 直到所有父类中都不存在, 抛出AttributeError.

如果类属性修改, 则实例中获取到的值, 也会变化. 

2. 实例属性的缺陷

直接把变量暴露出去, 好处是便于修改, 写起来方便.  随之而来的缺陷是, 可以被随意修改, 无法做参数检查,和一下动态的属性. 如下例, 

In [1]: class Square:
   ...:     def __init__(self, side):
   ...:         self.side = side
   ...:         self.area = side * side
In [2]: squ = Square(5)

In [3]: squ.side
Out[3]: 5
In [4]: squ.area
Out[4]: 25

定义一个正方形类, 有两个属性边长和面积. 对边长属性可以被置成负数显然是不可理的

In [5]: squ.side=-90

一个解决方法是, 通过添加方法set_side()来实现参数的校验. 

In [1]: class Demo:
   ...:     def __init__(self, side):
   ...:         self._side = side
   ...:     def set_side(self, length):
   ...:         self._side = max(length, 0)
   ...:     def get_side(self, length):
   ...:         return self._side 
   ...:     def get_area(self):
   ...:         return self._side * self._side

In [2]: demo = Demo(6)
In [3]: demo.get_area()
Out[3]: 36

In [4]: demo.set_side(-9)
In [5]: demo.get_side()
Out[5]: 0

这样写虽然实现了参数校验的功能, 需要调用函数来set_side设置和get_side返回属性的值, 调用起来复杂, 可读性来说也不是很友好.

3. 使用@property

@property装饰器会将方法转换为相同名称的属性, 使得你可以用获取属性的方式来调用方法. 

In [1]: class Demo:
   ...:     def __init__(self, side):
   ...:         self._side = side
   ...:     @property
   ...:     def side(self):
   ...:         return self._side
In [2]: demo =Demo(3)

In [3]: demo.side
Out[3]: 3
In [3]: demo.side = 90
AttributeError: can't set attribute

通过装饰器@property装饰了的side方法, 当执行demo.side的访问side属性时候,实际执行的是side()方法, side是只读属性, 尝试赋值的时候, 会报 AttributeError. 如果要对property赋值, 需要实现一个attr.setter的方法, 本例中attr就是side.

In [1]: class Demo:
   ...:     def __init__(self, side):
   ...:         self._side = side
   ...:     @property
   ...:     def side(self):
   ...:         return self._side
   ...:     @side.setter
   ...:     def side(self, value):
   ...:         self._side = max(value, 0)
   ...:     @property
   ...:     def area(self):
   ...:         return self._side * self._side

In [2]: demo = Demo(5)
In [3]: demo.area
Out[3]: 25

In [4]: demo.side = -8
In [5]: demo.side
Out[5]: 0
In [6]: demo.area
Out[6]: 0

总结

使用@property, 可以把一个方法变成属性调用, 这样

① 可以在属性的赋值和获取的时候添加例如格式校验等额外功能,

② 提供更加直观, 调用友好的代码.

使用方式:

@property装饰器实现属性的获取,  属性名.setter实现属性的赋值, 属性名.delete 实现属性的删除.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值