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

时间:2019-06-25 21:13:57

标签: 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()

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

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






THIS SHOULD PRINT ONCE

我想要的输出:

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

我正在尝试消除该函数的第二次调用。我知道我的错误出在装饰器上,我找不到它。

2 个答案:

答案 0 :(得分:4)

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

  • try/except块中。
  • 然后在return语句处一次。

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

res = func(*args, **kwargs)

然后简单地:

return res

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

由于您不是从except块抬起或返回,因此您必须在res内(在except内)分配None或在开始时预先定义它@Bean public PasswordEncoder passwordEncoder() { return NoOpPasswordEncoder.getInstance(); } 的修饰符(或适合您程序的任何值)。

答案 1 :(得分:3)

实际上,您两次打过电话,

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)
    return inner

您可能希望省略两者之一,并将结果存储在一个临时变量中,例如:

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:
            result = func(*args,**kwargs)
        except Exception as e:
            print("Error occured: {}".format(e))
            result = None

        print("#" * 40)
        print("End of output of {}".format(func.__name__))
        print("#" * 40)
        print("\n" * 5)
        return result
    return inner