python的装饰器是python的特色高级功能之一,言简意赅得说,其作用是在不改变其原有函数和类的定义的基础上,给他们增添新的功能。
装饰器存在的意义是什么呢?我们知道,在python中函数可以调用,类可以继承,为何要必须保证不改变函数和类的定义,就使得函数有了新的功能呢?其实很好解释。
提高代码的简洁程度与封装性。如果你采用新声明一个函数,并调用原来函数的思路使得原函数功能增加了,但是一方面使用起来看着不简洁, 另一方面当另一个程序员使用你的代码时再使用这样的思路,那代码嵌套无穷无尽,会让代码变得很乱,说不定改错了哪里,动了原函数哪个参数,就会出现发现不了的bug。
我们先来看一个简单的例子。
def addworld(func):
def addfun():
return func() + 'world'
return addfun() @addworld
def printhello():
return 'hello' print(printhello)
这段代码最后运行出来的结果是helloworld。我们发现,只要在原函数头上加一个你定义好了的增添功能的模板,以后凡是加上这个,都会增添一个功能,这提高了开发效率,也看着更加简洁。
def addnum(func):
def addfun(*args, **kwargs):
ret = func(*args, **kwargs)*2
return ret
return addfun @addnum
def printsum(a, b):
return (a+b) i = printsum(7, 7)
print(i)
这是有参数的情况下,装饰器的使用效果,输出结果为28。
def addnum1(c):
def addnum(func):
def addfun(*args, **kwargs):
ret = func(*args, **kwargs)*2*c
return ret
return addfun
return addnum @addnum1(5)
def printsum(a, b):
return (a+b) i = printsum(7, 7)
print(i)
装饰器本身也是可以传参的,在这个程序中,传入了一个常数5,最后得出的结果是140。
接下来,我们介绍几个常用的python内置装饰器。
property
在绑定属性时,如果我们直接把属性暴露出去,虽然写起来很简单,但是,没办法检查参数,导致可以把成绩随便改。这样显然是不行的,那么在函数中,我们往往如何提高程序的鲁棒性呢?
class Student(object): def get_score(self):
return self._score def set_score(self, value):
if not isinstance(value, int):
raise ValueError('score must be an integer!')
if value < 0 or value > 100:
raise ValueError('score must between 0 ~ 100!')
self._score = value s = Student()
s.set_score(60)
value = s.get_score()
print(value)
通过调用类中的函数从而进一步操作属性,这样虽然安全正确却未免看着复杂,不贴近人类自然的属性表现。
class Student(object): @property
def score(self):
return self._score @score.setter
def score(self, value):
if not isinstance(value, int):
raise ValueError('score must be an integer!')
if value < 0 or value > 100:
raise ValueError('score must between 0 ~ 100!')
self._score = value s = Student()
s.score = 80
print(s.score)
而加上一个@property就可以轻松解决这个问题,是不是很奇妙?把一个getter方法变成属性,只需要加上@property就可以了,此时,@property本身又创建了另一个装饰器@score.setter,负责把一个setter方法变成属性赋值,于是,我们就拥有一个可控的属性操作。
还可以定义只读属性,只定义getter方法,不定义setter方法就是一个只读属性。
class Student(object): @property
def birth(self):
return self._birth @birth.setter
def birth(self, value):
self._birth = value @property
def age(self):
return 2014 - self._birth
上面的birth是可读写属性,而age就是一个只读属性,因为age可以根据birth和当前时间计算出来。