[英]Use decorator to add an argument to the decorated function
Let's say I have a function foo
that logs some info during execution:假设我有一个函数foo
在执行期间记录一些信息:
import logging
logging.basicConfig()
def foo(x):
for i in range(10):
logging.info(f"This is iteration number {i}.")
x += i
return x
Is it possible to create a decorator log_or_not
so that I can call my decorated function foo
with an added argument like this:是否可以创建一个装饰器log_or_not
以便我可以调用我的装饰函数foo
并添加如下参数:
foo(level=logging.INFO)
For now all I have is this, a decorator that sets the logging level to INFO, executes the function then returns the logging level to the original level:现在我只有这个,一个将日志记录级别设置为 INFO 的装饰器,执行该函数然后将日志记录级别返回到原始级别:
def log_or_not(func):
def wrap_function(*args, **kwargs):
original_level = logging.root.level
print(original_level)
logging.getLogger().setLevel(logging.INFO)
y = func(*args, **kwargs)
logging.getLogger().setLevel(original_level)
return y
return wrap_function
@log_or_not
def foo(x):
for i in range(10):
logging.info(f"This is iteration number {i}.")
x += i
return x
Add the extra parameter to your wrap_function
:将额外参数添加到您的wrap_function
:
import logging
def log_or_not(func):
def wrap_function(*args, level=logging.INFO, **kwargs):
original_level = logging.root.level
print(original_level)
logging.getLogger().setLevel(level)
try:
return func(*args, **kwargs)
finally:
logging.getLogger().setLevel(original_level)
return wrap_function
Using try/finally
guarantees that you'll reset the original logging level after calling func
even if it raises an exception.使用try/finally
可以保证您在调用func
后重置原始日志记录级别,即使它引发了异常。
Since wrap_function
takes the place of the decorated function, you can now do:由于wrap_function
取代了装饰函数,您现在可以执行以下操作:
@log_or_not
def foo(x):
for i in range(10):
logging.info(f"This is iteration number {i}.")
x += i
return x
foo(0, level=logging.ERROR) # logs with level ERROR
foo(0) # logs with level INFO (default)
I would use a context manager to modify logging levels on the fly, and leave the function itself alone.我会使用上下文管理器来动态修改日志记录级别,而让函数本身保持独立。
import contextlib
# No try needed; the context manager decorator already
# ensures that the post-yield code is executed before
# propagating any exceptions.
@contextlib.contextmanager
def change_level(lvl):
original = logging.root.level
logging.getLogger().setLevel(lvl)
yield
logging.getLogger().setLevel(original)
# instead of foo(0, level=logging.ERROR)
with change_level(logging.INFO):
foo(0)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.