Python装饰器:让函数变得更加完美
Python装饰器是Python中一种提供代码重用的高级工具,可以用来增加函数的功能和灵活性。Python装饰器是将一个函数作为输入,通过运行一个或多个函数来修改其输入,然后在输出的新函数上返回修改后的结果。本文将介绍Python装饰器的概念及其在Python中的运用。
一、什么是Python装饰器
Python装饰器是一个可重用的函数,它可以修改或增强其他函数的行为。在Python中,任何函数都可以使用装饰器,其主要目的是为了使代码更加简洁、易读和易维护。装饰器的定义如下:
def decorator(func):
def wrapper(*args,**kwargs):
# 预处理
result = func(*args,**kwargs)
# 后处理
return result
return wrapper
上面的定义中,装饰器接受随后的函数作为参数,并返回新的函数。新的函数将执行以下步骤:
1. 执行预处理代码;
2. 调用原始函数;
3. 执行后处理代码;
4. 返回处理结果。
装饰器通常是一个函数,其返回一个函数,该函数可以获取和/或修改其他函数的行为,然后返回修改后的版本。 这使得整个代码变得更加简洁和易于维护,因为装饰器的代码在多个函数中可以使用和重复使用。
二、Python装饰器的实例
下面是一个示例,定义一个装饰器,用于计算函数的执行时间
import time
def timeit(func):
def wrapper(*args,**kwargs):
start_time = time.time()
result = func(*args,**kwargs)
end_time = time.time()
print("Time taken by function {} is {}".format(func.__name__, end_time-start_time))
return result
return wrapper
@timeit
def fib(n):
if n<=1:
return n
return fib(n-1) + fib(n-2)
print(fib(10))
代码中定义了一个timeit函数作为装饰器,并使用装饰器的语法@装饰器名来修饰函数fib,在函数执行前打印当前时间,函数执行结束后继续打印当前时间,并输出所需时间。执行结果如下:
Time taken by function fib is 5.9604644775390625e-05 Time taken by function fib is 9.5367431640625e-07 Time taken by function fib is 5.245208740234375e-05 Time taken by function fib is 5.030632019042969e-05 Time taken by function fib is 0.00012493133544921875 Time taken by function fib is 6.63e-05 Time taken by function fib is 7.152557373046875e-05 Time taken by function fib is 0.000125885009765625 Time taken by function fib is 0.00019741058349609375 Time taken by function fib is 0.00011801719665527344 55
从输出中可以看出,每次调用函数时,都会输出所需时间。这就是Python装饰器的魅力所在。
三、Python装饰器的常规用法
除了上面的示例之外,Python装饰器还有许多常规用法,这里简单介绍几种。
1. 记录函数执行次数
def count_calls(func):
def wrapper(*args,**kwargs):
wrapper.num_calls += 1
return func(*args,**kwargs)
wrapper.num_calls = 0
return wrapper
@count_calls
def fib(n):
if n<=1:
return n
return fib(n-1)+fib(n-2)
print(fib(10))
print(fib(20))
print(fib.num_calls)
上面的代码定义了一个可重用的函数count_calls,该函数接受一个函数,并返回一个新的函数wrapper,称为装饰器。新的函数作用是记录函数被调用的次数,并返回原始函数的执行结果。wrapper.num_calls保存计算器状态,并在每次调用函数时更新。输出结果如下:
55 6765 2
2. 确认函数返回的类型
def check_type(expected_type):
def decorator(func):
def wrapper(*args,**kwargs):
result = func(*args,**kwargs)
if isinstance(result,expected_type):
return result
else:
raise TypeError("Expected {} but got {}.".format(expected_type,result.__class__))
return wrapper
return decorator
@check_type(int)
def fib(n):
if n<=1:
return n
return fib(n-1) + fib(n-2)
print(fib(10))
上面的代码定义了一个装饰器check_type,用于检查函数返回值的类型,如果类型不为int,则抛出异常。输出结果如下:
55
3. 判断用户是否拥有访问权限
user_permission = {
"admin":True,
"user":False
}
def check_permission(permission):
def decorator(func):
def wrapper(*args,**kwargs):
if user_permission[permission]:
return func(*args,**kwargs)
else:
raise PermissionError("You don't have permission to access this resource.")
return wrapper
return decorator
@check_permission("admin")
def delete_all_records():
print("All records deleted.")
delete_all_records()
上面的代码定义了一个装饰器check_permission,用于检查用户是否有操作权限。如果有,则执行函数,否则抛出异常。输出结果如下:
All records deleted.
四、Python装饰器的注意事项
Python装饰器虽然功能强大,但在使用过程中需要注意以下几点:
1. 装饰器可以改变函数的行为,但不应该影响函数的返回值或传入参数的类型;
2. 装饰器本身应该是干净的,不包含可能影响函数的副作用;
3. 装饰器应该透明地将它所修饰的函数报告给其他希望使用的代码,例如使用__name__和__doc__属性;
4. 装饰器可以根据需要堆叠、重用和组合,但可能会产生一些不可预见的行为;
5. 装饰器可以使用N个变量,但这可能会使代码变得更加复杂。
经过对上述注意事项的观察,我们可以得出结论:Python装饰器是一种非常强大且有用的工具,可以使代码更加简洁、易于维护和复用。在使用装饰器时需要注意遵守一些规范和 实践,才能充分发挥其优点。
