我在编写测试代码的某些单元测试中使用函数装饰器。但是,我发现此装饰器使函数被调用两次(因此将其输出打印两次)。
在一些函数返回了错误的返回值之后,我才发现了这个错误,只有当函数被调用两次时才会发生。
#!/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
########################################
我正在尝试消除该函数的第二次调用。我知道我的错误出在装饰器上,我找不到它。
答案 0 :(得分:4)
请注意,您正在装饰器内部两次调用该函数:
try/except
块中。您希望将第一个调用(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