听到"装饰器"三个字总觉得是高深莫测的东西。网上各种教程一上来就是@符号、嵌套函数、闭包这些术语,看得人一头雾水。今天咱们就用大白话,把这个玩意儿讲讲明白喽,最后咱们再简单的写一个权限验证的装饰器。
一、从小白开始:什么是装饰器?
简单来说,装饰器就是给已有的函数"加外挂"的工具。比如你有一个函数,突然想给它增加记录运行时间的功能,但又不想修改这个函数本身的代码。这时候就能用上装饰器了。
装饰器就像给手机加个保护壳------手机本身没变,但多了层保护。在Python中,装饰器就是用@符号表示的那个东西。
先来看个最简单的例子:
python
import functools
def log_decorator(func):
"""日志装饰器"""
@functools.wraps(func)
def wrapper(*args, **kwargs):
print(f"调用参数:{func.__name__}")
print(f"参数:{args};kwargs={kwargs}")
result = func(*args, **kwargs)
print(f"返回值:{result}")
return result
return wrapper
# 使用装饰器
@log_decorator
def calculate_sum(n):
return sum(range(1, n + 1))
# 进行测试
result = calculate_sum(1000)
print(f"最终结果:{result}")
运行结果:
看明白了吗?log_decorator就像是给calculate_sum函数包了一层外挂,在函数执行前后加了点"佐料"。
二、进阶一点:装饰器是怎么工作的?
其实上面的@语法糖只是一种简便写法,本质上等价于:
python
def calculate_sum(n):
return sum(range(1, n + 1))
result = log_decorator(calculate_sum(n))
装饰器接收一个函数作为参数,然后返回一个新的函数来替代原来的函数。
三、带参数的装饰器
有时候我们想让装饰器本身也能接受参数。比如想要一个能重复执行函数指定次数的装饰器:
python
def repeat(times):
def decorator(func):
def wrapper(*args, **kwargs):
for i in range(times):
print(f"第{i+1}次执行")
result = func(*args, **kwargs)
return result
return wrapper
return decorator
@repeat(times=3)
def say_hello():
print("Hello!")
say_hello()
这里实际上有三层嵌套:最外层的repeat接收参数,返回一个装饰器函数decorator;decorator接收函数,返回wrapper函数。
四、实战:用装饰器实现权限验证
现在我们来点实际的。假设我们正在开发一个Web应用,有些页面需要登录才能访问,有些需要管理员权限。用装饰器来实现这个需求再合适不过了。
首先定义用户类型:
python
USER_ROLES = {
'anonymous': 0, # 匿名用户
'user': 1, # 普通用户
'admin': 2 # 管理员
}
class User:
def __init__(self, name, role):
self.name = name
self.role = role
current_user = User('张三', USER_ROLES['user']) # 模拟当前用户
然后编写权限验证装饰器:
python
def require_login(func):
def wrapper(*args, **kwargs):
if current_user.role == USER_ROLES['anonymous']:
return "请先登录!"
return func(*args, **kwargs)
return wrapper
def require_admin(func):
def wrapper(*args, **kwargs):
if current_user.role < USER_ROLES['admin']:
return "需要管理员权限!"
return func(*args, **kwargs)
return wrapper
现在我们可以轻松给函数加权限控制了:
python
@require_login
def view_profile():
return f"查看{current_user.name}的个人资料"
@require_admin
def delete_user(user_id):
return f"删除用户{user_id}成功"
print(view_profile()) # 正常访问
# print(delete_user(123)) # 需要管理员权限!
如果当前用户是普通用户,第一个函数能正常执行,第二个会返回"需要管理员权限!"的提示。
五、更好的方式:一个装饰器搞定多种权限
上面的写法虽然能用,但如果权限类型很多,我们要写很多类似的装饰器。我们可以改进一下,让一个装饰器支持多种权限级别:
python
def require_role(required_role):
def decorator(func):
def wrapper(*args, **kwargs):
if current_user.role < required_role:
role_name = [k for k, v in USER_ROLES.items() if v == required_role][0]
return f"需要{role_name}权限!"
return func(*args, **kwargs)
return wrapper
return decorator
# 使用方式
@require_role(USER_ROLES['user'])
def view_profile():
return f"查看{current_user.name}的个人资料"
@require_role(USER_ROLES['admin'])
def delete_user(user_id):
return f"删除用户{user_id}成功"
这样代码更加简洁和灵活了。
六、啰嗦一句
装饰器是Python中非常强大的特性,它允许我们不修改原有代码的情况下给函数添加新功能。从最简单的无参装饰器,到带参数的装饰器,再到今天的权限验证实战,希望大家对装饰器有更深的理解。
记住装饰器的核心思想:不修改原有代码,通过包装的方式扩展功能。