Python——函数装饰器导致函数被调用两次

bla*_*ndt 1 python python-3.x python-decorators

我在编写测试代码的一些单元测试中使用函数装饰器。但是,我发现这个装饰器会导致函数被调用两次(因此打印其输出两次)。

在某些函数返回错误的返回值后,我发现了这个错误,这种情况只有在调用函数两次时才会发生。

#!/usr/bin/env python3

def decorate(func):
    @wraps(func)
    def inner(*args, **kwargs):
        print("#" * 40)
        print("Testing function {}".format(func.__name__))
        print("Arguments passed: {} ".format(args))
        print("Begin output of {}".format(func.__name__))
        print("#" * 40)
        try:
            func(*args, **kwargs)
        except Exception as e:
            print("Error occured: {}".format(e))

        print("#" * 40)
        print("End of output of {}".format(func.__name__))
        print("#" * 40)
        print("\n" * 5)
        return func(*args,**kwargs) #Error happens on this line here
    return inner

#Add decorator to function definition. 
@decorate
def asdf():
    print("THIS SHOULD PRINT ONCE")

#Call function

asdf()
Run Code Online (Sandbox Code Playgroud)

输出(间距与复制的完全相同):

########################################
Testing function asdf
Arguments passed: ()
Begin output of asdf
########################################
THIS SHOULD PRINT ONCE
########################################
End of output of asdf
########################################






THIS SHOULD PRINT ONCE
Run Code Online (Sandbox Code Playgroud)

我想要的输出:

########################################
Testing function asdf
Arguments passed: ()
Begin output of asdf
########################################
THIS SHOULD PRINT ONCE
########################################
End of output of asdf
########################################
Run Code Online (Sandbox Code Playgroud)

我试图消除该函数的第二次调用。我知道我的错误在于装饰器,我只是找不到它。

Tom*_*koo 5

请注意,您从装饰器内部调用该函数两次:

  • 一旦进入try/except街区。
  • 并在返回语句处一次。

您需要将第一个调用(try 块中的调用)更改为:

res = func(*args, **kwargs)
Run Code Online (Sandbox Code Playgroud)

然后简单地:

return res
Run Code Online (Sandbox Code Playgroud)

编辑:(根据@DanielRoseman的评论)

由于您没有从except块中引发或返回,因此您必须res也在那里分配(在 内部except),或者在装饰器的开头预先定义它None(或任何适合您的程序的值)。

  • 尽管他们需要在“ except”块中定义 res 的默认值,否则如果 can 引发异常,则不会定义它 (5认同)