函数装饰器
一切皆对象
- 在Python中,变量的本质都是对象,字符串变量是一个
str
类型的对象,而函数同样是一个类型为 function
的变量。
def fun():
def fun():
print('函数fun')
fun()
#函数fun
#我们可以将一个函数赋值给一个变量
f = fun
f()
#函数fun
#它的本质是一个类型为function的对象
print(type(f))
#<class 'function'>
在函数中再定义一个函数
def fun1():
print('这里是fun1')
def fun2():
print('这里是fun2')
fun2()
fun1()
# 这里是fun1
# 这里是fun2
fun2()
# 这里调用fun2会报 NameError 的错误
# 这里说明fun2只能在函数中的调用,不能在函数外被调用。
从函数中返回一个函数
- 在上面例子中我们得知,嵌套函数(在函数中定义的函数)只能在定义它的函数体中被调用。那么有没有办法可以在函数的外部执行调用呢?
def fun1():
def fun2():
print('这里是fun2')
#将嵌套函数作为函数的返回值
return fun2
# 我们可以通过调用fun1函数,获得fun2函数的对象
f = fun1()
f()
# 这里是fun2
# fun1()() 与上述调用等同
将函数作为参数传入另一个函数
def fun1(fun):
print('在执行fun函数前做些事情')
# 调用传入的函数fun
fun()
def fun2():
print('fun2函数执行中')
# 将fun2函数作为参数传入fun1函数
fun1(fun2)
# 在执行fun函数前做些事情
# fun2函数执行中
编写第一个装饰器
# 定义一个装饰器
def decorator(fun):
def wrapper():
print("在执行 fun函数 前做一些事")
fun()
print("在执行 fun函数 后做一些事")
# 返回被装饰后的 fun函数
return wrapper
def hello():
print('hello python')
hello()
# hello python
# 使用 decorator函数 装饰 hello函数
hello_with_decorator = decorator(hello)
hello_with_decorator()
# 在执行 fun函数 前做一些事
# hello python
# 在执行 fun函数 后做一些事
- 糖语法:在上面的例子中,装饰器的使用过于繁琐,不利于阅读。为了更贴近装饰器的作用(在不改变函数体的前提下,对函数的功能进行扩展),我们通过糖语法来使用装饰器。
# 定义一个装饰器
def decorator(fun):
def wrapper():
print("在执行 fun函数 前做一些事")
fun()
print("在执行 fun函数 后做一些事")
# 返回被装饰后的 fun函数
return wrapper
# 糖语法
@decorator
def hello():
print('hello python')
hello()
# 在执行 fun函数 前做一些事
# hello python
# 在执行 fun函数 后做一些事
装饰带参数的函数
- 在上面的例子中装饰器所装饰的函数是没有参数的,而在大多数情况下函数是否有参数是不确定的,为了满足普适性,下面继续完善我们的装饰器。
# 定义一个装饰器
def decorator(fun):
# 使用不定长参数
def wrapper(*args, **kwargs):
print("在执行 fun函数 前做一些事")
fun(*args, **kwargs)
print("在执行 fun函数 后做一些事")
# 返回被装饰后的 fun函数
return wrapper
# 糖语法
@decorator
def hello(content: str):
print(content)
hello("hello python")
# 在执行 fun函数 前做一些事
# hello python
# 在执行 fun函数 后做一些事
带参数的装饰器
- 在一些比较复杂的应用场景中,为了满足开发需求,装饰器需要传入一些参数,那如何定义带参数的装饰器呢?
# 带参数的装饰器
def tag(name: str='<a>'):
def decorator(f):
# 使用不定长参数
def wrapper(*args, **kwargs):
content = f(*args, **kwargs)
return '{tag}{content}{tag}'.format(tag=name, content=content)
# 返回被装饰后的 fun函数
return wrapper
return decorator
@tag('<a>')
def hello(content: str = 'hello python'):
return content
print(hello("hello python"))
# <a>hello python<a>