Почему обернутая функция в этом декораторе запускается автоматически, и ни один из них не вызывается?

Я изучаю, как использовать декоратор в Python 3. Я набрал эти коды в редакторе и нажал кнопку "Выполнить".

log_stat = False


def decorator():
    def wrapper(func):
        global log_stat
        while not log_stat:
            username = input("username")
            password = input("password")
            if username == "123" and password == "456":
                func()
                log_stat = True
            else:
                print("try again")
    return wrapper


@decorator()
def welcome():                 
    print("welcome")

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

Какова реальная причина этого? И как я могу просто определить функцию, не вызывая упакованную?

2 ответа

Декоратор - это вызываемый объект, который принимает класс или функцию и возвращает класс или функцию. Синтаксис декоратора

@decorator  # note no ()
def function():
    ...

То, что вы делаете, звонит decoratorзатем, используя результат этого вызова (wrapper) декорировать welcome, wrapper поэтому бежит сразу.

То, что вы намеревались написать, было, вероятно,

def decorator(func):
    def wrapper(*args, **kwargs):
        global log_stat
        while not log_stat:
            username = input("username")
            password = input("password")
            if username == "123" and password == "456":
                log_stat = True
                return func(*args, **kwargs)           
            else:
                print("try again")  # I would raise an exception here
    return wrapper


@decorator
def welcome():                 
    print("welcome")

Обратите внимание, что wrapper принимает аргументы в этой версии. Это потому, что когда вы украшаете welcomeзаменяется на wrapper, Так что если ваш welcome функция взяла аргументы, ваш wrapper также придется принять их, чтобы передать их в исходную функцию.

Потому что вы вызвали декоратор при его использовании. Это означает, что он работает во время импорта. Вы должны удалить скобки.

@decorator
def welcome():                 
    print("welcome")

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

Другие вопросы по тегам