简介
定义:装饰器是特殊的闭包,特殊在于装饰器的参数除了可以是基本数据类型外,还可以是函数或类
作用:不改动原函数、不改变原函数调用方式的前提下,扩展函数功能,遵循了开放封闭原则
函数装饰器
需求一
版本一
# v1
def 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
变成闭包
# v2
def login(func):
def inner():
print("passed user vertification...")
func() # func是原tv()函数
return inner
def tv():
print("Welcome to tv page")
tv = login(tv)
tv()
等效于
# v2.1
def 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 res
return inner
@outer # @login等效于tv = login(tv)
def tv(name):
print("Welcome [%s] to tv page" % name)
return 6 # 有返回值
res = tv('hy') # 传入参数
print(res) # 6