我正在研究一个烧瓶后端中带有装饰器的函数,并考虑将其导入另一个脚本并以不同的方式装饰它。有人知道您导入它时会发生什么,无论装饰器是否附带它?
我看过this,但它正在讨论更多在同一脚本中发生的事情。
答案 0 :(得分:3)
否,导入装饰功能不会删除装饰器。
导入会从源模块的全局名称空间中检索当前对象,并且修饰函数会使修饰器返回值存储在全局名称空间中。
对于modulename = sys.modules['modulename']
(对于import modulename
)和objectname = sys.modules['modulename'].objectname
分配(对于from modulename import objectname
,无论哪种情况,导入模块都是主要语法糖首先确保sys.modules
已加载所需的模块),并且模块中的全局变量与模块对象上的属性相同。装饰只是functionname = decorator(functionobject)
的语法糖。
如果需要在导入的函数中添加新的装饰器,只需调用装饰器:
from somemodule import somedecoratedfunction
newname_or_originalname = decorator(somedecoratedfunction)
如果导入的修饰函数不适合在新层中再次修饰,或者您想访问原始的未修饰函数,请查看对象是否具有__wrapped__
属性:
from somemodule import somedecoratedfunction
unwrapped_function = somedecoratedfunction.__wrapped__
写得很好的修饰符使用@functools.wraps()
decorator,它将该属性设置为指向原始属性:
>>> from functools import wraps
>>> def demodecorator(f):
... @wraps(f)
... def wrapper(*args, **kwargs):
... print("Decorated!")
... return f(*args, **kwargs)
... return wrapper
...
>>> @demodecorator
... def foo(name):
... print(f"Hello, {name or 'World'}!")
...
>>> foo('cardamom')
Decorated!
Hello, cardamom!
>>> foo.__wrapped__('cardamom')
Hello, cardamom!
答案 1 :(得分:2)
装饰功能
@some_decorator
def some_func(...):
...
等同于将函数应用于另一个对象:
def some_func(...):
...
some_func = some_decorator(some_func)
导入模块时,您只能访问当前绑定到some_func
的对象,该对象是应用于原始函数的some_decorator
的返回值。除非返回的some_decorator
包含对原始未经修饰的函数的引用,否则您将无法从导入的模块访问它。
暴露原件的示例:
def some_decorator(f):
def _(*args, *kwargs):
# Do some extra stuff, then call the original function
# ...
return f(*args, **kwargs)
_.original = f
return _
@some_decorator
def some_func(...):
...
导入模块时,some_module.some_func
指的是修饰函数,但原始的未修饰函数可通过some_module.some_func.original
使用,但仅 ,因为装饰器是为它可用。 (正如Martijn Peters指出的那样,wraps
装饰器可以为您完成此操作以及其他一些不错的操作,但是装饰器仍然需要使用 wraps
。)< / p>