装饰器
参考:https://www.cnblogs.com/chenhuabin/p/11369359.html#_label1_0
一、定义
1.1 函数的四个特性
- 可以赋值给其他变量
- 可以作为参数传递给其他函数
- 可以在内部定义一个函数
- 可以当做返回值返回
装饰器的本质是函数,主要用来装饰其他函数,也就是为其他函数添加附加功能。
1.2 不用装饰器实现功能
def out_func(f): def inner_func(): print('{}函数开始运行……'.format(f.__name__)) f() print('{}函数结束运行……'.format(f.__name__)) return inner_func def func(): print('正在完成功能') if __name__ == '__main__': ceshi = out_func(func) ceshi()
1.3 使用装饰器实现功能
def out_func(f): def inner_func(): print('{}函数开始运行……'.format(f.__name__)) f() print('{}函数结束运行……'.format(f.__name__)) return inner_func @out_func def func(): print('正在完成功能') if __name__ == '__main__': func()
1.4 结论
加了out_func装饰器的func 等价于 out_func(func)
二、装饰器的优点
2.1 装饰器不能修改被装饰的函数的源代码,也就是可以在不对被装饰函数做任何修改的前提下,给被装饰函数附加上一些功能。
使用@out_func对func函数进行装饰时,我们没有对func函数的代码做什么的改变,但是被装饰后的func函数却多了开始运行和结束运行的功能。
2.2,装饰器不能修改被装饰的函数的调用方式。在被装饰前,我们通过func调用这个函数,被装饰后,还是通过func调用这个函数。
2.3 代码更加精简。在上面代码中,我们只是用@out_func装饰了func一个函数,但是如果有多个函数需要添加开始运行和结束运行的提示功能,如果不用装饰器,那么就需要对每一个函数进行修改,则工作量和需要修改的代码量……
用了装饰器之后,只需要在需要添加这一功能的函数前面添加@func就可以了。
总之:一言以盖之,装饰器可以在不改变原函数调用方式和代码情况下,为函数添加一些功能,使代码更加精简。
我们使用装饰器来实现统计一个函数的运行时间的功能
import time def timmer(f): def inner_func(): start_time = time.time() f() end_time = time.time() print('{}函数运行消耗时间为:{}'.format(f.__name__, end_time-start_time)) return inner_func @timmer def func(): print('do_something函数运行……') time.sleep(1) if __name__ == '__main__': func()
三、深入理解装饰器
3.1 被修饰的函数带返回值
def out_func(f): def inner_func(): print('{}函数开始运行……'.format(f.__name__)) ret = f() print('{}函数结束运行……'.format(f.__name__)) return ret # 这里返回值 return inner_func @out_func def dec_dunc(): print('正在完成功能') return '我是返回值' if __name__ == '__main__': ret = dec_dunc() print(ret)
3.2 被装饰函数带参数
def out_func(f): def inner_func(name): print('{}函数开始运行……'.format(f.__name__)) ret = f(name) print('{}函数结束运行……'.format(f.__name__)) return ret return inner_func @out_func def func(name): print('你好,{}!'.format(name)) return '我是返回值' if __name__ == '__main__': ret = func('世界') print(ret)
如果无法理解就理解成out_func(func)。
3.3 装饰器函数带参数
def key_language(key='python'): def out_func(f): def inner_func(name): if key == 'python': print('{}函数开始运行……'.format(f.__name__)) else: print("关键字出错") ret = f(name) if key == 'python': print('{}函数结束运行……'.format(f.__name__)) else: print("关键字出错") return ret return inner_func return out_func @key_language('python') def func(name): print('你好,{}!'.format(name)) return '我是返回值' if __name__ == '__main__': ret = func('世界') print(ret)
3.3 多层装饰器
import time def timmer(f): def inner_func(): print("timer开始运行") start_time = time.time() f() end_time = time.time() print('{}函数运行消耗时间为:{}'.format(f.__name__, end_time-start_time)) return inner_func def out_func(f): def inner_func(): print('{}函数开始运行……'.format(f.__name__)) ret = f() print('{}函数结束运行……'.format(f.__name__)) return inner_func @out_func @timmer def func(): print("我是被装饰函数") time.sleep(1) if __name__ == '__main__': func()
注意运行顺序,下面的装饰器优先于上面的装饰器运行。
先运行f()之前的代码,下层装饰器优先运行;再运行f()代码;在运行f()之后的代码,依然是下层装饰器优先运行。
3.4 类装饰器
import time class A(): def __init__(self, t): print('实例化一个A类对象……') self.t = t def __call__(self, f): def inner_A(x): print('延迟{}秒后开始执行……'.format(self.t)) time.sleep(self.t) print('{}函数开始运行……'.format(f.__name__)) f(x) print('{}函数结束运行……'.format(f.__name__)) return inner_A @A(1) def func(name): print('你好,{}!'.format(name)) if __name__ == '__main__': func('姚明')
四、 内饰装饰器
4.1 @property,@setter,@deleter
@property装饰器所装饰的函数可以像访问属性一样调用函数,注意,@property装饰器必须先于@setter,@deleter使用,且三者说装饰的函数必须同名。
class A(): def __init__(self, v): print('实例化一个A类对象……') self.__value = v @property def value(self): print('取值时被调用') return self.__value @value.setter def value(self, value): print('赋值时被调用') self.__value = value @value.deleter def value(self): print('删除值时被调用……') del self.__value if __name__ == '__main__': a = A(123) print('-------------') print('__value的值为:{}'.format(a.value)) print('-------------') a.value = 234 print('__value的值为:{}'.format(a.value)) print('--------------') del a.value # print('__value的值为:{}'.format(a.value)) # 执行会报错