简介
定义:装饰器是特殊的闭包,特殊在于装饰器的参数除了可以是基本数据类型外,还可以是函数或类
作用:不改动原函数、不改变原函数调用方式的前提下,扩展函数功能,遵循了开放封闭原则
函数装饰器
需求一
版本一
# v1def login(func):print("passer user vertification...")return func # func是原tv()函数def tv():print("Welcome to tv page")tv = login(tv)# tv的值为tv函数的内存地址,这里把tv函数当作变量传给login函数,属于高阶函数操作tv()
注解:想给tv()函数加个功能login(),但是我不想改变原函数的调用方式,调用方式依然是tv()
# v1.1:换成装饰器def login(func):print("passer user vertification...")return func # func是原tv()函数@login # @login等效于tv = login(tv)def tv():print("Welcome to tv page")tv()
版本二
被加入的功能函数login变成闭包
# v2def login(func):def inner():print("passed user vertification...")func() # func是原tv()函数return innerdef tv():print("Welcome to tv page")tv = login(tv)tv()
等效于
# v2.1def login(func):def inner():print("passed user vertification...")func() # func是原tv()函数return inner@login # @login等效于tv = login(tv)def tv():print("Welcome to tv page")tv()
注解:演示到这里,貌似差不多了,剩下的就是把参数传进去和返回回来
需求二
版本三
需求一 + 传递参数 + 返回值
# v3.1# func无返回值+普通参数def login(func):def inner(args): # 参数其实传到了这里print("passed user vertification...")func(args) # func是原tv()函数return inner@login # @login等效于tv = login(tv)def tv(name):print("Welcome [%s] to tv page" % name)tv('hy') # 传入参数
参数太死了,不够灵活,改成动态参数*args, **kwargs
# v3.2# func无返回值+动态参数def login(func):def inner(*args, **kwargs): # 参数其实传到了这里print("passed user vertification...")func(*args, **kwargs) # func是原tv()函数return inner@login # @login等效于tv = login(tv)def tv(name):print("Welcome [%s] to tv page" % name)tv('hy') # 传入参数
那我想获取返回值怎么办?inner()函数加个return func
# v3.3 推荐版本# func有返回值+动态参数def login(func):def inner(*args, **kwargs): # 参数其实传到了这里print("passed user vertification...")return func(*args, **kwargs) # func是原tv()函数return inner@login # @login等效于tv = login(tv)def tv(name):print("Welcome [%s] to tv page" % name)return 6 # 有返回值res = tv('hy') # 传入参数print(res) # 6
这里,已经把装饰器的原理和常用用法阐述清楚了,如果遇到更复杂的装饰器,也是可以理解并加以运用的
最终版本
顺便说一下,装饰器的应用场景,一般就是在原函数的前面或者后面加上自定义代码,比如登录前的登录模块代码,那我想再 登录、看完电视后,还想睡觉怎么办,你这里只在前面加了代码啊
# 最终版# func有返回值+动态参数def outer(func):def inner(*args, **kwargs): # 参数其实传到了这里print("前面的代码") # 可替换成任意类型的代码:单行或多行代码、函数、类等res = func(*args, **kwargs) # func是原tv()函数print("后面的代码") # 替换成任意类型的代码:单行或多行代码、函数、类等return resreturn inner@outer # @login等效于tv = login(tv)def tv(name):print("Welcome [%s] to tv page" % name)return 6 # 有返回值res = tv('hy') # 传入参数print(res) # 6
