欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Python中的@property装饰器

程序员文章站 2022-12-17 08:10:13
要了解@property的用途,首先要了解如何创建一个属性。 一般而言,属性都通过__init__方法创建,比如: 创建实例,运行结果: 但是这样子有2个坏处: 1.__init__ 中定义的属性是可变的,如果一个系统的开发人员在知道属性名的情况下,就可以进行随意更改(尽管可能是在无意识的情况下), ......

要了解@property的用途,首先要了解如何创建一个属性。

一般而言,属性都通过__init__方法创建,比如:

1 class student(object):
2     def __init__(self,name,score):
3         self.name=name
4         self.score=score

创建实例,运行结果:

1 tim=student('tim',97) 
2 tim.score=100
3 tim.score 
4 100 
5 mary=student('mary',90) 
6 mary.score 
7 90

但是这样子有2个坏处:

1.__init__ 中定义的属性是可变的,如果一个系统的开发人员在知道属性名的情况下,就可以进行随意更改(尽管可能是在无意识的情况下),如果一不小心篡改了,后台排查很难!

2.不利于进行参数检查,比如:score属性范围本该是[0,100],但如果输成了1000也不会报错。

因此,一个标准的创建属性流程如下:

1.定义三个跟属性(本例中是score)相关的函数:

get(用于返回score属性)

set(用于设定score属性)

del(用于删除score属性)

在set函数中,可以添加一些取值范围,比如[0,100].此外,为了私有化属性,前面可以加上__。

这样就做到了既能通过创建实例设定属性,又不让开发人员轻易修改score属性。

如下所示:

 1 class student(object):
 2     def getscore(self):
 3         return self.__score
 4     
 5     def setscore(self,score):
 6         if score>100 or score<0:
 7             raise valueerror ('score is out of range.')
 8         else:
 9             self.__score=score
10     
11     def delscore(self):
12         del self.__score

这样,一旦score取值不在设定范围内,就会报错!

创建一个实例,能够正常运行:

1 mary=student()
2 mary.setscore(90)
3 mary.getscore()
4 90

但是,通过方法getscore()查看分数似乎还是有点繁琐,能不能把它当作一个属性去调用呢?至少调用不需要输入()嘛!

当然是可以的。

办法就是通过装饰器:@property

通过给getscore,setscore,delscore三个方法分别添加三个装饰器,就可以直接把这三个方法作为属性去调用了!

如下所示:

 1 class student(object):
 2     @property
 3     def getscore(self):
 4         return self.__score
 5     @getscore.setter
 6     def setscore(self,score):
 7         if score>100 or score<0:
 8             raise valueerror ('score is out of range.')
 9         else:
10             self.__score=score
11     @getscore.deleter
12     def delscore(self):
13         del self.__score
1 tim=student()
2 tim.setscore=90
3 tim.getscore
4 90

非常神奇!方法居然变成了属性,为什么呢?

因为装饰器@property本质上是一个property()函数,property()函数也是一个装饰器。

一般的装饰器是用在普通函数上,而@property是用在类内的方法上。

property()函数包含了三个部分:getter,setter,deleter。

因为setter和deleter是property()的第二和第三个参数,不能直接套用@语法。

因此,本质上@property相当于getter部分,@setscore.setter相当于setter部分,@delscore.deleter相当于deleter部分。

所以,上面的代码本质上等价于:

 1 class student(object):
 2     def getscore(self):
 3         return self.__score
 4     
 5     def setscore(self,score):
 6         if score>100 or score<0:
 7             raise valueerror ('score is out of range.')
 8         else:
 9             self.__score=score
10     
11     def delscore(self):
12         del self.__score
13     
14     score=property(getscore,setscore,delscore,'description')

最后,为了函数名美观,可以把函数名字改成score():

 1 class student(object):
 2     @property
 3     def score(self):
 4         return self.__score
 5     @score.setter
 6     def score(self,score):
 7         if score>100 or score<0:
 8             raise valueerror ('score is out of range.')
 9         else:
10             self.__score=score
11     @score.deleter
12     def delscore(self):
13         del self.__score
14 
15 tim=student()
16 tim.score=90
17 tim.score
18 90

 几篇个人觉得写的比较清楚的文章:

http://www.runoob.com/python/python-func-property.html

https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/00143186781871161bc8d6497004764b398401a401d4cce000

https://www.cnblogs.com/cicaday/p/python-decorator.html