- mongodb - 在 MongoDB mapreduce 中,如何展平值对象?
- javascript - 对象传播与 Object.assign
- html - 输入类型 ="submit"Vs 按钮标签它们可以互换吗?
- sql - 使用 MongoDB 而不是 MS SQL Server 的优缺点
我们的代码根据运行时参数调用可变数量的上下文管理器:
from contextlib import nested, contextmanager
@contextmanager
def my_context(arg):
print("entering", arg)
try:
yield arg
finally:
print("exiting", arg)
def my_fn(items):
with nested(*(my_context(arg) for arg in items)) as managers:
print("processing under", managers)
my_fn(range(3))
但是,contextlib.nested
is deprecated since Python 2.7 :
DeprecationWarning: With-statements now directly support multiple context managers
Multiple variables in Python 'with' statement 的答案表明 contextlib.nested
有一些“令人困惑的容易出错的怪癖”,但使用多管理器 with
语句的建议替代方法不适用于可变数量的上下文管理器(并且还破坏了向后兼容性)。
contextlib.nested
是否有任何替代品未被弃用并且(最好)没有相同的错误?
或者我应该继续使用 contextlib.nested
并忽略警告?如果是这样,我是否应该计划在将来的某个时间删除 contextlib.nested
?
最佳答案
新的Python 3 contextlib.ExitStack
class被添加为 contextlib.nested()
的替代品(参见 issue 13585 )。
它的编码方式可以让你直接在 Python 2 中使用它:
import sys
from collections import deque
class ExitStack(object):
"""Context manager for dynamic management of a stack of exit callbacks
For example:
with ExitStack() as stack:
files = [stack.enter_context(open(fname)) for fname in filenames]
# All opened files will automatically be closed at the end of
# the with statement, even if attempts to open files later
# in the list raise an exception
"""
def __init__(self):
self._exit_callbacks = deque()
def pop_all(self):
"""Preserve the context stack by transferring it to a new instance"""
new_stack = type(self)()
new_stack._exit_callbacks = self._exit_callbacks
self._exit_callbacks = deque()
return new_stack
def _push_cm_exit(self, cm, cm_exit):
"""Helper to correctly register callbacks to __exit__ methods"""
def _exit_wrapper(*exc_details):
return cm_exit(cm, *exc_details)
_exit_wrapper.__self__ = cm
self.push(_exit_wrapper)
def push(self, exit):
"""Registers a callback with the standard __exit__ method signature
Can suppress exceptions the same way __exit__ methods can.
Also accepts any object with an __exit__ method (registering a call
to the method instead of the object itself)
"""
# We use an unbound method rather than a bound method to follow
# the standard lookup behaviour for special methods
_cb_type = type(exit)
try:
exit_method = _cb_type.__exit__
except AttributeError:
# Not a context manager, so assume its a callable
self._exit_callbacks.append(exit)
else:
self._push_cm_exit(exit, exit_method)
return exit # Allow use as a decorator
def callback(self, callback, *args, **kwds):
"""Registers an arbitrary callback and arguments.
Cannot suppress exceptions.
"""
def _exit_wrapper(exc_type, exc, tb):
callback(*args, **kwds)
# We changed the signature, so using @wraps is not appropriate, but
# setting __wrapped__ may still help with introspection
_exit_wrapper.__wrapped__ = callback
self.push(_exit_wrapper)
return callback # Allow use as a decorator
def enter_context(self, cm):
"""Enters the supplied context manager
If successful, also pushes its __exit__ method as a callback and
returns the result of the __enter__ method.
"""
# We look up the special methods on the type to match the with statement
_cm_type = type(cm)
_exit = _cm_type.__exit__
result = _cm_type.__enter__(cm)
self._push_cm_exit(cm, _exit)
return result
def close(self):
"""Immediately unwind the context stack"""
self.__exit__(None, None, None)
def __enter__(self):
return self
def __exit__(self, *exc_details):
# We manipulate the exception state so it behaves as though
# we were actually nesting multiple with statements
frame_exc = sys.exc_info()[1]
def _fix_exception_context(new_exc, old_exc):
while 1:
exc_context = new_exc.__context__
if exc_context in (None, frame_exc):
break
new_exc = exc_context
new_exc.__context__ = old_exc
# Callbacks are invoked in LIFO order to match the behaviour of
# nested context managers
suppressed_exc = False
while self._exit_callbacks:
cb = self._exit_callbacks.pop()
try:
if cb(*exc_details):
suppressed_exc = True
exc_details = (None, None, None)
except:
new_exc_details = sys.exc_info()
# simulate the stack of exceptions by setting the context
_fix_exception_context(new_exc_details[1], exc_details[1])
if not self._exit_callbacks:
raise
exc_details = new_exc_details
return suppressed_exc
使用它作为你的上下文管理器,然后随意添加嵌套上下文管理器:
with ExitStack() as stack:
managers = [stack.enter_context(my_context(arg)) for arg in items]
print("processing under", managers)
对于您的示例上下文管理器,这将打印:
>>> my_fn(range(3))
('entering', 0)
('entering', 1)
('entering', 2)
('processing under', [0, 1, 2])
('exiting', 2)
('exiting', 1)
('exiting', 0)
您也可以安装 contextlib2
module ;它包含 ExitStack
作为后向端口。
关于python - 使用可变数量的上下文管理器替代 contextlib.nested,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16083791/
自从我知道了这个模式,我就一直在使用 with open('myfile.txt','w') as myfile: with contextlib.redirect_stdout(myfile
我在 Ubuntu 上使用 Python3.5。以下脚本创建一个文件 out 并用越来越多的“Hello”行填充它: import contextlib with contextlib.redirec
我正在尝试创建一个包装器来使上下文对象成为可选的。当条件为真时,事物应该表现得像包装的上下文对象,否则它应该表现得像无操作上下文对象。此示例适用于使用一次包装对象,但失败了,它被重新使用。 例子: i
我明白了why contextlib.nested is deprecated . 但是如果我为旧的 python 版本编写程序而没有 with 的多种形式(即 < 2.7),我(几乎)别无选择。 为
有谁知道我在哪里可以找到这个 python 模块“contextlib”? root@overo:~# python
我们的代码根据运行时参数调用可变数量的上下文管理器: from contextlib import nested, contextmanager @contextmanager def my_cont
为什么我可以跳过在 yield log_func 中调用 log_func,即我可以只写 yield 而代码仍然有效。这是为什么? yield 在这种情况下如何工作? import time from
假设我有一个上下文管理器: @contextmanager def cm(x): y = f(x) z = yield y g(z) 如何将 z 发送到上下文管理器? 我试过:
我使用 Python2.7 并且我想要函数:contextlib.redirect_stdout . 我的意思是,我想重定向特定函数的输出(不是所有程序)。 问题是 - 只有 Python3 支持“c
作为将我的游戏引擎代码转换为 cython 的一部分,我正在移植我的顶点缓冲区对象 (Vbo) 类。我使用这个 Vbo 类将 3D 模型数据发送到 GPU。代码 (vbo.pyx) 当前如下所示: c
我在 python 中使用 with 语句( PEP 343 ) 时遇到了一些问题,以便在上下文之后自动管理资源清理。特别是,with 语句 始终假定资源清理方法是 .close()。 IE。在下面的
为了以编程方式组合上下文管理器,我使用以下代码: == helpers.py == from contextlib import nested import mock def multiple_pat
context.nested 已被弃用,我试图理解这背后的基本原理,在阅读了很长时间的文档后,我看不到一个例子来说明第二个问题: Secondly, if the __enter__() method
我真的很喜欢“with open('in_file'') as f”这个语法。我想将该语法用于必须打开和关闭的我自己的资源。 但是,我不明白如何更改我的 open() 方法以启用“with”语法。我可
from contextlib import closing def init_db(): with closing(connect_db()) as db: with app
尝试从 docker 运行命令时,我遇到了这个错误 google 计算引擎上的 docker 容器。 这是堆栈跟踪: Traceback (most recent call last): File
为了以编程方式组合上下文管理器,我使用以下代码: == helpers.py == from contextlib import nested import mock def multiple_pat
为了说明我的问题,这里有一个不使用 contextlib 的基本请求: import urllib.request url = "http://www.example.com/"
在寻找性能错误的过程中,我终于确定问题的根源是 contextlib 包装器。开销相当惊人,我没想到这是减速的根源。减速在 50 倍的范围内,我无法承受循环。如果它有可能显着减慢速度,我肯定会感谢文档
为什么要使用 contextlib.suppress 来抑制异常,而不是使用 try/except 和 pass? 这两种方法在字符数量上没有区别(如果有的话,suppress 有更多的字符),即使代
我是一名优秀的程序员,十分优秀!