被装饰者如何访问装饰器名称?以foo与a_decorator为例
在被装饰函数内部获取装饰器名称的实现方法
当然可以做到!这里有几种可靠的方式让你的foo函数获取到装饰器a_decorator的名称,从而打印出Called a_decorator,我会逐一说明实现思路和代码示例:
方法一:给被装饰函数添加自定义属性
这是最常用的方式,装饰器在包装原函数时,给返回的包装器(wrapper)添加一个存储装饰器名称的属性,被装饰后的函数可以直接访问这个属性。
import functools def a_decorator(func): @functools.wraps(func) # 保留原函数的元信息(比如__name__),避免混淆 def wrapper(*args, **kwargs): return func(*args, **kwargs) # 给包装器添加装饰器名称属性 wrapper._decorator_name = a_decorator.__name__ return wrapper @a_decorator def foo(): # 直接访问被装饰后函数的自定义属性 print(f'Called {foo._decorator_name}') foo() # 输出:Called a_decorator
关键说明:
functools.wraps(func)不是必须的,但它能让wrapper继承原函数func的元数据(比如foo.__name__还是'foo'而不是'wrapper'),让代码更规范。- 我们给
wrapper添加了_decorator_name属性,因为@a_decorator语法糖执行后,foo变量实际指向的是wrapper函数,所以可以直接通过foo._decorator_name获取装饰器名称。
方法二:通过参数传递装饰器名称
如果希望更显式地传递信息,可以让装饰器在调用原函数时,把装饰器名称作为参数传入,被装饰函数直接接收这个参数即可。
方式A:显式定义参数
def a_decorator(func): def wrapper(*args, **kwargs): # 调用原函数时传入装饰器名称 return func(*args, decorator_name=a_decorator.__name__, **kwargs) return wrapper @a_decorator def foo(decorator_name): print(f'Called {decorator_name}') foo() # 输出:Called a_decorator
方式B:用关键字参数兼容原函数签名
如果不想修改原函数的参数列表,可以用**kwargs来接收装饰器传递的参数:
def a_decorator(func): def wrapper(*args, **kwargs): kwargs['decorator_name'] = a_decorator.__name__ return func(*args, **kwargs) return wrapper @a_decorator def foo(**kwargs): decorator_name = kwargs.get('decorator_name') if decorator_name: print(f'Called {decorator_name}') foo() # 输出:Called a_decorator
被装饰者(decoratee)访问装饰器名称的核心逻辑
总结一下,被装饰函数要获取装饰器名称,本质上有两种路径:
- 属性访问:装饰器在包装过程中,将自身名称绑定到被装饰后的函数对象上,被装饰函数直接访问该属性。
- 参数传递:装饰器在调用被装饰函数时,主动将自身名称作为参数传入,被装饰函数通过参数接收。
两种方式各有优劣:
- 属性访问方式不需要修改被装饰函数的签名,更隐蔽,适合不想对外暴露参数的场景。
- 参数传递方式更直观,代码可读性更高,适合需要明确传递上下文信息的场景。
内容的提问来源于stack exchange,提问作者00__00__00
相关产品推荐
相关产品推荐

