Python Decorators время импорта - PullRequest
0 голосов
/ 19 мая 2019

Я регистрирую некоторые из моих функций в глобальном наборе:

# registry.py
import functools

schedule_registry = set()


def register_scheduler(func):
    @functools.wraps(func)
    def func_wrapper():
        print(f"adding {func.__name__}")
        schedule_registry.add(func)
        return func

    return func_wrapper


@register_scheduler
def foo():
    print("running foo")

Теперь я ожидаю, что schedule_registry будет заполнено во время импорта (и будет напечатано "добавление ..."), но к моему удивлению:

In [1]: import registry                                                                                                                                                                                           

In [2]:  

Ничего не печатается.

Дело в том, если я изменю декоратор на следующее:

def register_scheduler():
    def func_wrapper(func):
        print(f"adding {func.__name__}")
        schedule_registry.add(func)
        return func

    return func_wrapper

@register_scheduler()
def foo():
    print("running foo")

Я получаю то, что ожидаю:

In [1]: import registry                                                                                                                                                                                           
adding foo

Ответы [ 2 ]

1 голос
/ 19 мая 2019

Для выполнения вашей задачи: добавляя в набор, но не меняя поведение, вам не нужны functools. Вместо этого вам просто нужна простая функция, которая возвращает вашу функцию.

Попробуйте это на:

schedule_registry = set()

def register_scheduler(func):
  print(f"adding {func.__name__}")
  schedule_registry.add(func)
  return func

@register_scheduler
def foo():
    print("running foo")

@register_scheduler
def bar():
    print("running bar")

print(f"now running foo..., and registry has {len(schedule_registry)} items")

foo()

И вы должны увидеть:

adding foo
adding bar
now running foo..., and registry has 2 items
running foo
1 голос
/ 19 мая 2019

Это не имеет ничего общего с wraps.

Вы не поняли, как работают декораторы. Внешняя функция вызывается во время импорта и возвращает внутреннюю функцию, которая заменяет декорируемую функцию. Внутренняя функция затем вызывается вместо исходной функции, поэтому она должна принимать свои исходные аргументы - , а не func. Если вы хотите, чтобы что-то происходило во время импорта, оно должно идти во внешней функции.

def register_scheduler(func):
    print(f"adding {func.__name__}")
    schedule_registry.add(func)

    @functools.wraps(func)
    def func_wrapper(*args, **kwargs):
       print(f"at call time")
       return func(*args, **kwargs)
    return func_wrapper

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

...