Python 装饰器机制的核心!
简要来说,decorator(func)这一步,是装饰器实际发挥作用的环节。下面详细解析:
一、装饰器的本质流程
当你写:
@get("/")
def homepage():
print("Homepage")
Python 其实做了以下事情:
- 运行
def homepage(): ...语句,创建函数对象homepage; - 运行
get("/"),返回一个新的函数:decorator; - 调用
decorator(homepage),返回值(可能是原函数,也可能是新函数)赋值给名字homepage。
所以最终
homepage这个名字,大多数场合下已经不是你原来定义的函数了,而是装饰器返回的那个(包裹或者加工后的)新函数。
二、为什么 decorator(func) 能“拿到”原函数?
Python 的函数本身就是对象,你可以像变量一样传递:
def hello():
print("hi")
x = hello # 这时 x 和 hello 都指向同一个函数对象
x() # 输出 hi
装饰器利用这一点,直接把原始函数对象传给装饰器的参数(如:func)。你可以对 func 做任何操作,比如记录、包裹、加工、替换。
三、装饰器执行流程图
以@get("/")为例:
def get(path):
def decorator(func):
print(f"注册函数 {func.__name__} 到 {path}")
return func
return decorator
@get("/test")
def myfunc():
print("in myfunc")
执行步骤:
- Python 先定义
myfunc,得到其函数对象 - 运行
get("/test"),得到decorator这个函数 - 调用
decorator(myfunc),把myfunc对象作为参数func传入 decorator里就拿到了myfunc,可以做任何操作,比如注册、包裹等- 返回值(比如原函数/包裹函数)会再次赋值给
myfunc这个名字
四、简单例子验证
def outer(func):
print("我拿到了函数对象:", func)
return func
@outer
def foo():
print("我是foo")
输出:
我拿到了函数对象: <function foo at 0x...>
五、装饰器的本质作用
- 你传入的是“函数对象”,装饰器可以:
- 登记注册(比如放到字典里)
- 返回新函数(比如加日志、权限检查等功能,实际调用的是返回的新函数)
总结
- decorator(func) 之所以能拿到原函数,是因为Python允许将函数对象作为参数传递;
- 这样装饰器内部可以自由利用、操作和返回新的函数对象,达到“钩住和加工”原方法的目的,完成注册或包装等各种花式功能!
如果你还想了解装饰器和元编程更底层的原理,也可以继续问我!