1. 什么是装饰器
在Python中,装饰器是一种很有用的语法机制,它允许对函数、类或语句进行修饰,以增加或修改它们的功能。其本质上是一个函数,其输入和输出都是函数,用于提供一种在不改变原有函数定义的情况下增强函数能力的方法。
简单来说,装饰器是用于修饰一些已有的函数或方法的语法结构。
def my_decorator(func):
def wrapper():
print("Before function is called.")
func()
print("After function is called.")
return wrapper
@my_decorator
def say_hello():
print("Hello!")
say_hello()
在上面的例子中,@my_decorator
的作用相当于为say_hello()
函数添加了my_decorator()
函数作为修饰器。 运行这个修饰后的函数,会输出如下结果:
Before function is called.
Hello!
After function is called.
2. 装饰器的优点
使用装饰器的主要优点是能够更好地组织代码,并提高代码的可读性和重用性。下面是几个具体的例子:
2.1 函数计时器
装饰器可以使得函数计时更加方便,不用在代码中加入额外的计时代码。
import time
def timing_function(some_function):
def wrapper():
t1 = time.time()
some_function()
t2 = time.time()
print("Time it took to run the function:", t2 - t1, "seconds")
return wrapper
@timing_function
def my_function():
num_list = []
for num in range(0, 10000):
num_list.append(num)
print("Sum of all the numbers:", sum(num_list))
my_function()
在该例子中,@timing_function
函数为my_function
函数添加了一个计时器,以便测量函数运行所需的时间。
2.2 日志记录器
另一个常见的例子是使用装饰器来记录函数的日志。 使用装饰器的好处是,您可以将所有的日志代码放在一个单独的位置,并使用不同的修饰器轻松地为多个函数添加日志记录。
def log_decorator(func):
def wrapper(*args, **kwargs):
print("Function '{}' called.".format(func.__name__))
result = func(*args, **kwargs)
print("Function '{}' finished.".format(func.__name__))
return result
return wrapper
@log_decorator
def add(x, y):
return x + y
@log_decorator
def subtract(x, y):
return x - y
print(add(3,4))
print(subtract(4,1))
在这个例子中,我们使用@log_decorator
函数来为add
和subtract
函数添加日志记录器。log_decorator
函数为这些函数提供了一个统一的方式来记录它们的运行情况,从而可以更轻松地维护和调试代码。
3. 如何编写装饰器
编写装饰器的常见步骤如下:
编写装饰器函数,该函数应在其内部定义一个封装函数并返回该函数。
封装函数应包括原始函数的所有参数,并在其内部调用原始函数。
在封装函数中添加修饰器代码。
返回封装函数。
在需要修饰的函数添加修饰器。
3.1 带参数的装饰器
装饰器还可以带参数,这样就可以按需自定义函数行为。
def custom_decorator(param):
def inner_decorator(function):
def wrapper():
print("Decorated with:", param)
function()
return wrapper
return inner_decorator
@custom_decorator("abc")
def say_hello():
print("Hello world")
say_hello()
使用装饰器语法将函数包装在装饰器内并提供参数来对其进行自定义。
3.2 支持任意数量参数和关键字参数的装饰器
如果要支持任意数量参数和关键字参数,则需要使用*args
和**kwargs
来接收和传递这些参数。
def my_decorator(some_function):
def wrapper(*args, **kwargs):
print("Something is happening before the function is called.")
result = some_function(*args, **kwargs)
print("Something is happening after the function is called.")
return result
return wrapper
@my_decorator
def my_function(a, b):
return a + b
print(my_function(2, 3))
在以上代码中,修饰器可以处理任何数量和类型的参数,因为其使用*args
和**kwargs
来传递参数。
4. 装饰器的应用场景
装饰器的使用场景非常广泛。在这里列举了几个经典的例子:
4.1 权限控制
权限控制是一种非常常见的需求,装饰器可以非常方便地管理它。当使用@login_required
时,只允许已登录的用户访问特定的页面或执行操作。
from functools import wraps
from flask import abort
from flask_login import current_user
def admin_required(func):
@wraps(func)
def decorated_view(*args, **kwargs):
if not current_user.is_admin:
abort(403)
return func(*args, **kwargs)
return decorated_view
@app.route('/admin/dashboard')
@admin_required
def admin_dashboard():
return "Admin dashboard"
上面的代码使用@admin_required
装饰器来只允许管理员访问后台仪表板。
4.2 缓存函数
在一些请求量较大的网站上,为了避免频繁查询数据库,可以使用缓存装饰器来缓存函数调用结果,减少访问数据库的次数。另外,这样子的话还可以提高访问速度。
import time
def cached(timeout=10):
def decorator(func):
def wrapper(*args, **kwargs):
key = str(args) + str(kwargs)
if key in wrapper.cache and time.time() - wrapper.cache[key]["time"] < timeout:
return wrapper.cache[key]["value"]
else:
value = func(*args, **kwargs)
wrapper.cache[key] = {"value": value, "time": time.time()}
return value
wrapper.cache = {}
return wrapper
return decorator
@cached()
def slow_function():
time.sleep(5)
return 42
print("Running the function the first time...")
print(slow_function())
print("Running the function the second time...")
print(slow_function())
在以上代码中,我们提供了一个缓存装饰器来缓存大量计算时间长的函数结果,以减小服务器压力。
5. 总结
装饰器是Python语言中的一个重要特性,它能够极大地拓展Python的语言功能。 通过使用装饰器,我们可以在不改变函数的原貌情况下增加或修改函数功能,从而提高代码可读性、可重用性、可维护性。
有了装饰器语法,我们可以轻松支持带参数和任意数量参数和关键字参数的函数。 装饰器还有许多应用,例如缓存函数、权限控制等。 因此,了解装饰器是Python开发人员的重要一步。