对于日志记录,我希望每个函数在函数的开头和结尾都记录自己的名称。
def my_function():
print("Enter my_function")
# ...
print("Leave my_function")
如果我更改了该功能的名称,我也必须更新这些打印消息。我正在寻找一种自动化的方法。
def my_decorator(func):
print("Enter ", func.__name__)
func()
print("Leave ", func.__name__)
def my_function():
# do the work
pass
# main:
my_decorator(my_function)
这可能是一个简单的方法,也许使用装饰器?如果my_function有参数,那会怎么样?
答案 0 :(得分:8)
你是对的,使用装饰器是实现这种行为的完美方式。
你需要知道的是装饰器是如何工作的:它只是将一个函数作为参数,并返回另一个函数。这个其他返回函数用于包装你的参数函数。
def log_in_out(func):
def decorated_func(*args, **kwargs):
print("Enter ", func.__name__)
result = func(*args, **kwargs)
print("Leave ", func.__name__)
return result
return decorated_func
@log_in_out
def my_function():
print("Inside my_function")
return 42
val = my_function()
print(val)
# Output:
# Enter my_function
# Inside my_function
# Leave my_function
# 42
另请注意,@ŁukaszRogalski使用his anwser post的答案对于保留函数docstring非常有用。
最后,来自@MartinBonner的一个好主意是,您还可以使用它来记录函数中的错误:
def log_in_out(func):
def decorated_func(*args, **kwargs):
name = func.__name__
print("Enter", name)
try:
result = func(*args, **kwargs)
print("Leave", name)
except:
print("Error in", name)
raise
return result
return decorated_func
请注意,我重新抛出错误,因为我认为应该从函数外部管理控制流。
对于更高级的日志记录,您应该使用提供许多功能的functools.wraps
。
答案 1 :(得分:1)
当然,对于星球和星球来说,它真的很简单。 functools.wraps
用于将任何元数据(__name__
,__doc__
等)从输入函数重写为包装器。如果函数对象字符串表示对您来说过于冗长,则可以改为使用print("Enter", f.__name__)
。
import functools
def d(f):
@functools.wraps(f)
def wrapper(*args, **kwargs):
print("Enter", f)
result = f(*args, **kwargs)
print("Exit", f)
return result
return wrapper
@d
def my_func():
print("hello")
@d
def my_func2(x):
print(x)
my_func()
my_func2("world")
输出:
Enter <function my_func at 0x10ca93158>
hello
Exit <function my_func at 0x10ca93158>
Enter <function my_func2 at 0x10caed950>
world
Exit <function my_func2 at 0x10caed950>