如果从另一个脚本导入经过修饰的python函数会怎样?

时间:2019-03-12 14:45:09

标签: python python-3.x decorator

我正在研究一个烧瓶后端中带有装饰器的函数,并考虑将其导入另一个脚本并以不同的方式装饰它。有人知道您导入它时会发生什么,无论装饰器是否附带它?

我看过this,但它正在讨论更多在同一脚本中发生的事情。

2 个答案:

答案 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>