前置知识:
- 函数的本质就是变量名
- 可以把函数作为参数传递,例如:
def func():
print("我是func")
# 接收的fn是个函数
def handle(fn):
# 调用函数
fn()
handle(func)
- 可以把函数作为返回值返回,例如
def func():
def func2():
print("我是func2")
# func2函数作为返回值
return func2
fn = func()
fn()
闭包
闭包:内层函数对外层函数的变量的使用
作用1:让一个变量被外部访问,但是不能修改
作用2:让一个变量常驻内存
def func():
a = 10
def inner():
print(a)
return a
return inner
# 函数外部访问到了变量a
fn = func()
fn()
装饰器
本质: 装饰器的本质就是一个函数,该函数的参数是被装饰的函数,返回值是装饰后的函数
作用: 装饰器可以在不改变原有代码的基础上,给函数添加新的功能
一、装饰器雏形(理解)
装饰器雏形
def wrapper(fn):
def inner():
print("执行被装饰函数之前")
fn()
print("执行被装饰函数之后")
return inner
def add():
print("我是add")
# 向wrapper函数传入了add函数,返回的函数命名为add
add = wrapper(add) # 装饰器的关键语句!!!
add() # 这里执行add()相当于执行inner(),因为wrapper返回的是inner函数
装饰器雏形用语法糖的形式写
def wrapper(fn):
def inner():
print("执行被装饰函数之前")
fn()
print("执行被装饰函数之后")
return inner
@wrapper # 用语法糖/装饰器的写法应该这么写,等价于执行add = wrapper(add)
def add():
print("我是add")
add() # 这里执行add()相当于执行inner(),因为wrapper返回的是inner函数
二 、通用装饰器(重点记住)
通用装饰器的固定写法如下:
(wrapper、inner、fn都是可以随意命名的,并非固定的)
def wrapper(fn):
# *args和**kwargs用于接受被装饰函数的参数
def inner(*args, **kwargs):
"""在被装饰函数之前执行的操作"""
# 注意:这里的*和**是将args和**kwargs打散传递给fn函数
ret = fn(*args, **kwargs) # 被装饰函数
"""在被装饰函数之后执行的操作"""
return ret # 处理被装饰函数的返回值
return inner
三、高阶装饰器(理解)
即同一个函数被多个装饰器装饰,按照就近原则解读。
举例:
def wrapper1(fn):
def inner(*args, **kwargs):
print("wrapper1-before")
ret = fn(*args, **kwargs)
print("wrapper1-after")
return ret
return inner
def wrapper2(fn):
def inner(*args, **kwargs):
print("wrapper2-before")
ret = fn(*args, **kwargs)
print("wrapper2-after")
return ret
return inner
@wrapper2
@wrapper1
def target():
print("我是target")
"""
先被wrapper1装饰,再被wrapper2装饰
因此target()函数运行的打印结果为:
wrapper2-before
wrapper1-before
我是target
wrapper1-after
wrapper2-after
"""
target()
四、带参数的装饰器(理解)
在通用装饰器的外面再套一层函数,传入需要的参数,然后返回这个装饰器。
举例:
def wrapper_outer(name):
def wrapper(fn):
def inner(*args, **kwargs):
print(f"wrapper-before-{name}")
ret = fn(*args, **kwargs)
print(f"wrapper-after-{name}")
return ret
return inner
return wrapper
# wrapper_outer("啦啦啦")相当于运行了这个函数,返回了一个装饰器
# 在装饰器前面再加个@来使用装饰器,装饰对应的函数
@wrapper_outer("啦啦啦")
def target1():
print("我是target1")
@wrapper_outer("哦哦哦")
def target2():
print("我是target2")
target1()
target2()