在讲装饰器前先简短带大家回顾一下闭包的概念。
闭包
满足以下三个条件:
- 闭包函数 定义在函数内部
- 使用了外部函数的变量
- 外部函数返回了该内部函数
下面这段代码中,prompt就是一个闭包函数。
# 代码1
def eat():
food = "香蕉"
def prompt():
print(food)
return prompt
eat()
装饰器
装饰器的作用:在不修改原函数代码的基础上为原函数增加新功能。
执行流程:
1. 装饰器接收一个函数,并存着
2. 装饰器返回一个闭包函数
3. 闭包函数被调用,执行其对应的代码。
一个装饰器修饰函数
"""定义一个装饰器,用于输出提示信息"""
def prompt(func):
def inner():
print("加法运算:")
func()
return inner
@prompt
def add(a=1, b=2):
print(a + b)
add()
# 输出
加法运算:
3
上面这段程序执行过程:
- 当Python解释器读到
@prompt
装饰器时,它会立即执行prompt
函数,并将add
函数作为参数传递给它。 prompt
函数定义了inner
函数,并将其作为闭包返回。- 装饰器
@prompt
的作用完成后,add
的名字不再指向原始的add
函数,而是指向了prompt
返回的inner
函数。 - 最后,当代码执行到
add()
时,实际上是在调用inner
函数。 - 在
inner
函数中,它会首先打印出"加法运算:",然后调用原始的add
函数。
多个装饰器修饰函数
注意:装饰器是靠近函数定义的装饰器开始向上执行(即从下往上执行)。
def action(func):
print('action', func)
def out1(actions='狗刨'):
func() # 这里调用的是out函数
print('游泳动作: %s' % actions)
return out1
def eat(func):
print('eat', func)
def out(food='香蕉'):
func() # 这里调用的是animal函数
print('吃: %s' % food)
return out
@action
@eat
def animal(animals='猴子'):
print(animals)
animal() # 这里调用的是迭代器action返回的out1()
# 输出
eat <function animal at 0x000001CBEFFE5800>
action <function eat.<locals>.out at 0x000001CBEFFE58A0>
猴子
吃: 香蕉
游泳动作: 狗刨
程序执行过程:
- 因为是从下往上执行,所以先执行
@eat,在执行@action。
- Python执行到
@eat
装饰器时,eat
装饰器被调用,其参数是animal
函数。 - 接下来,
@action
装饰器被调用,其参数是eat
装饰器返回的out
函数。 - 最终,
animal
函数变替换成out1
函数,然后在animal()这行开始调用。