当我们谈论 Python 中的装饰器时,我们实际上是在讨论一种高级函数。装饰器允许开发人员动态地修改函数或类的行为,而无需直接修改它们的代码。这种特性使得装饰器在许多常见的编程场景中非常有用,比如日志记录、性能测试、权限验证等。
Python装饰器是一种强大的功能,它允许您动态地修改类或函数的行为。为了深入了解装饰器,我们需要先了解闭包。
闭包是指在函数中再嵌套一个函数,并且内部函数引用了外部函数的变量。例如:
def outer(x):
def inner(y):
return x + y
return inner
print(outer(2)(3))
# 输出:5
在这个示例中,outer
函数内部定义了 inner
函数,并且 inner
函数引用了外部函数 outer
的变量 x
。因此,outer(6)(5)
返回 2 + 3
的结果。
装饰器实际上就是一种闭包的应用。它是一个用于扩展原函数功能的函数,而且其返回值也是一个函数。通过使用装饰器,可以在不修改原函数代码的情况下给函数增加新的功能。例如:
def debug(func):
def wrapper():
print("[DEBUG]: enter {}()".format(func.__name__))
return func()
return wrapper
@debug
def hello():
print("hello")
hello()
# 输出:
# [DEBUG]: enter hello()
# hello
在这个例子中,装饰器
debug
给函数hello
加上了进入函数的debug模式,而无需修改原函数的代码。
装饰器也可以接受参数,装饰的函数也可以传递参数。例如:
def logging(level):
def outwrapper(func):
def wrapper(*args, **kwargs):
print("[{0}]: enter {1}()".format(level, func.__name__))
return func(*args, **kwargs)
return wrapper
return outwrapper
@logging(level="INFO")
def hello(a, b, c):
print(a, b, c)
hello("hello,","good","morning")
# 输出:
# [INFO]: enter hello()
# hello, good morning
在这个示例中,装饰器
logging
接受一个参数level
,然后返回一个完整的装饰器。同时被装饰的函数hello
也传递了三个参数。
__call__
魔法方法来实现类的直接调用。例如:class logging(object):
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
print("[DEBUG]: enter {}()".format(self.func.__name__))
return self.func(*args, **kwargs)
@logging
def hello(a, b, c):
print(a, b, c)
hello("hello,","good","morning")
# 输出:
# [DEBUG]: enter hello()
# hello, good morning
类装饰器也可以带参数,例如:
class logging(object):
def __init__(self, level):
self.level = level
def __call__(self, func):
def wrapper(*args, **kwargs):
print("[{0}]: enter {1}()".format(self.level, func.__name__))
return func(*args, **kwargs)
return wrapper
@logging(level="TEST")
def hello(a, b, c):
print(a, b, c)
hello("hello,","good","morning")
# 输出:
# [TEST]: enter hello()
# hello, good morning
在这个例子中,my_timer 装饰器函数添加了计时功能,会在执行函数时输出函数的执行时间。
import time
def my_timer(original_function):
def wrapper(*args, **kwargs):
t1 = time.time()
result = original_function(*args, **kwargs)
t2 = time.time() - t1
print('{} ran in: {} sec'.format(original_function.__name__, t2))
return result
return wrapper
@my_timer
def display_info(name, age):
time.sleep(1)
print('display_info ran with arguments ({}, {})'.format(name, age))
display_info('Fiang', 22)