Что произойдет, если вы импортируете украшенную функцию Python из другого скрипта? - PullRequest
1 голос
/ 12 марта 2019

Я смотрю на функцию в бэкэнде колбы с декоратором и думаю импортировать ее в другой скрипт и декорировать ее другим способом. Кто-нибудь знает, что происходит, когда вы импортируете его, идет ли с ним декоратор или нет?

Я посмотрел на это , но он обсуждает больше того, что происходит в том же сценарии.

Ответы [ 2 ]

3 голосов
/ 12 марта 2019

Нет, импорт декорированной функции не удалит декоратор.

При импорте извлекается текущий объект из глобального пространства имен исходного модуля, а декорирование функции вызывает возвращаемое значение декораторадля хранения в глобальном пространстве имен.

Импорт модуля - это в основном синтаксический сахар для modulename = sys.modules['modulename'] (для import modulename) и objectname = sys.modules['modulename'].objectname назначений (для from modulename import objectname, либо вcase после первого, гарантирующего, что 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!
2 голосов
/ 12 марта 2019

Декорирование функции

@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, но только , потому что декоратор был написан, чтобы сделать его доступным.(Как отмечает Мартин Питерс, декоратор wraps делает это - и некоторые другие приятные вещи - для вас, но декоратору все еще нужно использовать wraps.)

...