为什么在这个装饰器中包装的函数自动运行而没有一个都不被调用?

时间:2019-01-29 15:51:51

标签: python python-3.x function python-decorators syntactic-sugar

我正在探索如何在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 个答案:

答案 0 :(得分:3)

装饰器是可调用的,它接受一个类或函数并返回一个类或函数。装饰器语法为

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

您正在做的是调用decorator,然后使用该调用的结果(wrapper)装饰welcomewrapper因此立即运行。

您打算写的是

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也必须接受它们才能将其传递给原始函数。

答案 1 :(得分:1)

因为您在使用装饰器时已将其调用。这意味着它在导入时运行。您应该删除括号。

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

(可以定义一个在导入时被调用的装饰器,因为它接受参数;但是要这样做,您必须实现另一层包装,以便该函数返回一个装饰器,该装饰器又返回一个函数包裹原始文件。)