Python 函数装饰器 | 菜鸟教程
CSDN:python装饰器详解
简言之,python装饰器就是用于拓展原来函数功能的一种函数,这个函数的特殊之处在于它的返回值也是一个函数,使用python装饰器的好处就是在不用更改原函数的代码前提下给函数增加新的功能。
def hi(name="yasoob"):
return "hi " + name
print(hi())
# output: 'hi yasoob'
# 我们甚至可以将一个函数赋值给一个变量,比如
greet = hi
# 我们这里没有在使用小括号,因为我们并不是在调用hi函数
# 而是在将它放在greet变量里头。我们尝试运行下这个
print(greet())
# output: 'hi yasoob'
# 如果我们删掉旧的hi函数,看看会发生什么!
del hi
print(hi())
#outputs: NameError
print(greet())
#outputs: 'hi yasoob'
在函数中定义函数:
def hi(name="yasoob"):
print("now you are inside the hi() function")
def greet():
return "now you are in the greet() function"
def welcome():
return "now you are in the welcome() function"
print(greet())
print(welcome())
print("now you are back in the hi() function")
hi()
#output:now you are inside the hi() function
# now you are in the greet() function
# now you are in the welcome() function
# now you are back in the hi() function
# 上面展示了无论何时你调用hi(), greet()和welcome()将会同时被调用。
# 然后greet()和welcome()函数在hi()函数之外是不能访问的,比如:
greet()
#outputs: NameError: name 'greet' is not defined
ef hi(name="yasoob"):
def greet():
return "now you are in the greet() function"
def welcome():
return "now you are in the welcome() function"
if name == "yasoob":
return greet
else:
return welcome
a = hi()
print(a)
#outputs:
#上面清晰地展示了`a`现在指向到hi()函数中的greet()函数
#现在试试这个
print(a())
#outputs: now you are in the greet() function
这里需要注意的是:在 if/else
语句中我们返回 greet
和 welcome
,而不是 greet()
和 welcome()
。因为当你把一对小括号放在后面,这个函数就会执行;然而如果你不放括号在它后面,那它可以被到处传递,并且可以赋值给别的变量而不去执行它。
例如:当我们执行hi()()
时,相当于首先执行hi()
,此时hi()
返回greet
,再加一个小括号,相当于执行greet()
def hi():
return "hi yasoob!"
def doSomethingBeforeHi(func):
print("I am doing some boring work before executing hi()")
print(func())
doSomethingBeforeHi(hi)
#outputs:I am doing some boring work before executing hi()
# hi yasoob!
这里的doSomethingBeforeHi
在每个被传入的函数执行之前都会打印一句话来指示正在执行的程序
def a_new_decorator(a_func):
def wrapTheFunction():
print("I am doing some boring work before executing a_func()")
a_func()
print("I am doing some boring work after executing a_func()")
return wrapTheFunction
def a_function_requiring_decoration():
print("I am the function which needs some decoration to remove my foul smell")
a_function_requiring_decoration()
#outputs: "I am the function which needs some decoration to remove my foul smell"
a_function_requiring_decoration = a_new_decorator(a_function_requiring_decoration)
#now a_function_requiring_decoration is wrapped by wrapTheFunction()
a_function_requiring_decoration()
#outputs:I am doing some boring work before executing a_func()
# I am the function which needs some decoration to remove my foul smell
# I am doing some boring work after executing a_func()
a_new_decorator
的作用就是在特定函数执行前后都打印一句话来指示函数将要执行和执行完毕,当我们希望每一次的调用函数都使用这两个指示,最基础的做法就是调用```a_new_decorator``将要使用的函数作为参数传入,也就是上述的
a_new_decorator(a_function_requiring_decoration)
def a_new_decorator(a_func):
def wrapTheFunction():
print("I am doing some boring work before executing a_func()")
a_func()
print("I am doing some boring work after executing a_func()")
return wrapTheFunction
@a_new_decorator
def a_function_requiring_decoration():
"""Hey you! Decorate me!"""
print("I am the function which needs some decoration to "
"remove my foul smell")
a_function_requiring_decoration()
#outputs: I am doing some boring work before executing a_func()
# I am the function which needs some decoration to remove my foul smell
# I am doing some boring work after executing a_func()
#the @a_new_decorator is just a short way of saying:
a_function_requiring_decoration = a_new_decorator(a_function_requiring_decoration)
在函数a_function_requiring_decoration()
的定义前有这么一句@a_new_decorator
,这就是装饰器,我们会发现,在直接调用a_function_requiring_decoration()
时,就会打印我们期望的指示函数调用的两句话,类似于:
在函数a_function_requiring_decoration()
的定义前加上@a_new_decorator
,在执行a_function_requiring_decoration()
时,默认执行的是@a_new_decorator(a_function_requiring_decoration)
需要注意的是,此时如果我们执行:
print(a_function_requiring_decoration.__name__)
# Output: wrapTheFunction
会发现,Ouput
输出应该是"a_function_requiring_decoration",但是却输出了wrapTheFunction
,我的理解是这样的:
不管是执行a_function_requiring_decoration()
,还是单纯作为一个对象a_function_requiring_decoration
被调用/传递,这个函数在定义前加上了@a_new_decorator
,就等于它的本质已经不是a_function_requiring_decoration
而是a_new_decorator(a_function_requiring_decoration)
,所以
a_function_requiring_decoration.__name__=a_new_decorator(a_function_requiring_decoration).__name__=wrapTheFunction.__name__
a_function_requiring_decoration()=a_new_decorator(a_function_requiring_decoration)()=wrapTheFunction()
这种情况下,装饰器的函数会重写了我们函数的名字和注释文档(docstring)
如果你不想函数被装饰器中的函数替代,可以使用Python提供给我们的一个简单的函数,那就是functools.wraps
一个python函数也可以被多个装饰器修饰,要是有多个装饰器时,这些装饰器的执行顺序是怎么样的呢?
def decorator1(func):
return lambda:"<1>"+func()+"<1>"
def decorator2(func):
return lambda:"<2>"+func()+"<2>"
@decorator1
@decorator2
def func():
return "hello"
print(func())
#<1><2>helllo<2><1>
因此,当函数被多个装饰器修饰时,执行的顺序为先执行离函数定义近的,再执行离函数定义远的。
前面的例子都是使用本质为函数的装饰器去装饰其他的函数,其实也可以使用类的定义去定义一个装饰器
class Decorator(object):
def __init__(self, f):
self.f = f
def __call__(self):
print("decorator start")
self.f()
print("decorator end")
@Decorator
def func():
print("func")
func()
#decorator start
#func
#decorator end
from functools import wraps
def a_new_decorator(a_func):
@wraps(a_func)
def wrapTheFunction():
print("I am doing some boring work before executing a_func()")
a_func()
print("I am doing some boring work after executing a_func()")
return wrapTheFunction
@a_new_decorator
def a_function_requiring_decoration():
"""Hey yo! Decorate me!"""
print("I am the function which needs some decoration to "
"remove my foul smell")
print(a_function_requiring_decoration.__name__)
# Output: a_function_requiring_decoration