python - 如何使用@contextmanager(包装器)作为标准函数
问题描述
这个问题类似于Python:标准函数和上下文管理器?,但略有不同。
我有许多类,每个类都定义了几个@contextmanagers:
class MyClass:
@contextmanager
def begin_foo(param):
[some code]
yield
[some code]
[...]
我还有一个 API 模块作为类的外观。在 API 模块中,我发现我需要“包装”内部上下文管理器,以便可以在客户端代码中使用它们:
@contextmanager
def begin_foo(param):
with myobj.begin_foo(param):
yield
我的客户端代码现在看起来像这样:
# Case 1: Some things need to be done in the context of foo
with begin_foo(param):
[ stuff done in the context of foo ]
# Case 2: Nothing needs to be done in the context of foo --
# just run the entry and exit code
with begin_foo(param):
pass
问题:有没有办法在第二种情况下使用 begin_foo 作为标准函数,而不需要 with ... pass 构造?即这样做:
# Case 2: Nothing needs to be done in the context of foo --
# just run the entry and exit code
begin_foo(param)
如果需要,我可以在 API 模块和/或类中更改 begin_foo 的实现。
解决方案
函数的默认contextmanager
装饰器的问题在于,除非在上下文中,否则无法同时调用和代码,正如您所知道的:__enter__
__exit__
with
from contextlib import contextmanager
@contextmanager
def foo_bar():
print('Starting')
yield
print('Finishing')
return False
>>> with foo_bar():
... print('in between')
...
Starting
in between
Finishing
>>> foo_bar() # only returns the cm if merely invoked
<contextlib._GeneratorContextManager at 0x517a4f0>
您可以创建另一个函数来执行进入和退出,对于任何厘米 - 我很惊讶这还不存在:
def in_out(cm, *args, **kwargs):
print('getting in')
with cm(*args, **kwargs):
print("we're in")
>>> in_out(foo_bar)
getting in
Starting
we're in
Finishing
或者,将您的类中的许多上下文管理器中的每一个重新实现为它们自己的上下文管理器类,并像在ContextDecorator
文档示例中一样使用它们,其中包括作为 cm 的调用和作为单个直接调用:
from contextlib import ContextDecorator class mycontext(ContextDecorator): def __enter__(self): print('Starting') return self def __exit__(self, *exc): print('Finishing') return False >>> @mycontext() ... def function(): ... print('The bit in the middle') ... >>> function() Starting The bit in the middle Finishing >>> with mycontext(): ... print('The bit in the middle') ... Starting The bit in the middle Finishing
推荐阅读
- java - Java JUnit测试实现分支覆盖
- elasticsearch - ElasticSearch => 如何使用 update_by_query 更新部分文档
- php - 基于产品数量的 ACF 转发器在 Woocommerce 中生成结帐字段
- struts2 - Struts1 标签到 Struts2 标签
- bash - unix,未附加电子邮件附件
- django - 防止 Django 表创建迁移到只读数据库
- php - 如何根据用户在 php 中的输入更改变量的值?
- html - 使用纯 CSS 的视差多个 DIV
- c++ - 如何排除故障:未定义的引用`non-virtual thunk to ...`
- ios - 通过 AVAssetDownloadTask/Session 下载后如何更新 AVURLAsset 的元数据?