Jor*_*ter 5 python contextmanager
假设我有一些我正在使用的上下文管理器(来自第三方库):
with freeze_time(test_dt):
lines_of_code_1
lines_of_code_2
lines_of_code_3
Run Code Online (Sandbox Code Playgroud)
但是,假设如果test_dt没有值,则上下文管理器不应该运行,但是所有剩余的代码都应该运行,如下所示:
if test_dt:
with freeze_time(test_dt):
lines_of_code_1
lines_of_code_2
lines_of_code_3
else:
lines_of_code_1
lines_of_code_2
lines_of_code_3
Run Code Online (Sandbox Code Playgroud)
假设lines_of_code
这里有2-3行完全相同的代码,是否有更清晰的写法呢?我知道我可以这样写:
def do_thing():
lines_of_code_1
lines_of_code_2
lines_of_code_3
if test_dt:
with freeze_time(test_dt):
do_thing()
else:
do_thing()
Run Code Online (Sandbox Code Playgroud)
但我对这种格式并不感到疯狂.另外,我不想在我的代码中乱丢这个模式.
最后一种可能性,但我不确定它是否会起作用:如果给出的test_dt为空,则继承上下文管理器并跳过__enter__
和__exit__
函数,如下所示:
class optional_freeze_time(object):
def __init__(self, test_dt=None):
if test_dt:
self.ctx_manager = freeze_time(test_dt)
else:
self.ctx_manager = None
def __enter__(self, *args, **kwargs):
if self.ctx_manager:
self.ctx_manager.__enter__(*args, **kwargs)
def __exit__(self, *args, **kwargs):
if self.ctx_manager:
self.ctx_manager.__exit__(*args, **kwargs)
Run Code Online (Sandbox Code Playgroud)
我用一个空白的上下文管理器类测试了它,它似乎行为正确.但是,如果我这样做,我担心真正的上下文管理器是否会正常运行(我对它的工作方式不太熟悉).
这是一种简单的方法来包装现有的上下文管理器,甚至不使用任何类:
from contextlib import contextmanager
@contextmanager
def example_context_manager():
print('before')
yield
print('after')
@contextmanager
def optional(condition, context_manager):
if condition:
with context_manager:
yield
else:
yield
with example_context_manager():
print(1)
with optional(True, example_context_manager()):
print(2)
with optional(False, example_context_manager()):
print(3)
Run Code Online (Sandbox Code Playgroud)
输出:
before
1
after
before
2
after
3
Run Code Online (Sandbox Code Playgroud)
新访问者可能对contextlib.ExitStack感兴趣:
with ExitStack() as stack:
if condition:
stack.enter_context(freeze_time(...))
lines_of_code_1
lines_of_code_2
lines_of_code_3
Run Code Online (Sandbox Code Playgroud)
此with
语句之后,freeze_time
仅在条件为真时才相关。