我们有代码根据运行时参数调用可变数量的上下文管理器:
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))
Run Code Online (Sandbox Code Playgroud)
但是,contextlib.nested自Python 2.7以来已弃用:
DeprecationWarning: With-statements now directly support multiple context managers
Run Code Online (Sandbox Code Playgroud)
Python'with '语句中的多个变量的答案表明contextlib.nested存在一些"令人困惑的容易出错的怪癖",但建议使用多管理器with语句的替代方法不适用于可变数量的上下文管理器(并且还会破坏向后兼容性) ).
是否有任何替代品contextlib.nested不被弃用,并且(最好)没有相同的错误?
或者我应该继续使用contextlib.nested并忽略警告?如果是这样,我是否应该计划contextlib.nested在将来的某个时间将其删除?
__exit__()即使存在异常,是否可以确保调用该方法__enter__()?
>>> class TstContx(object):
... def __enter__(self):
... raise Exception('Oops in __enter__')
...
... def __exit__(self, e_typ, e_val, trcbak):
... print "This isn't running"
...
>>> with TstContx():
... pass
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in __enter__
Exception: Oops in __enter__
>>>
Run Code Online (Sandbox Code Playgroud)
编辑
这是我能得到的尽可能接近......
class TstContx(object):
def __enter__(self):
try:
# __enter__ code
except Exception as e
self.init_exc = e
return self
def __exit__(self, e_typ, e_val, trcbak): …Run Code Online (Sandbox Code Playgroud) 如何在Python中处理在另一个上下文管理器中创建的上下文管理器?
示例:假设您具有A充当上下文管理器的类B,以及充当上下文管理器的类.但是类B实例必须实例化并使用类的实例A.我已经通过了PEP 343,这是我想到的解决方案:
class A(object):
def __enter__(self):
# Acquire some resources here
return self
def __exit__(seplf, exception_type, exception, traceback):
# Release the resources and clean up
pass
class B(object):
def __init__(self):
self.a = A()
def __enter__(self):
# Acquire some resources, but also need to "start" our instance of A
self.a.__enter__()
return self
def __exit__(self, exception_type, exception, traceback):
# Release the resources, and make our instance of A clean up as well
self.a.__exit__(exception_type, …Run Code Online (Sandbox Code Playgroud) Python教我们使用__enter__和对对象进行清理__exit__.如果我需要创建一个使用对象的对象,必须使用上下文管理器怎么办?想象一下:
from database1 import DB1
from database2 import DB2
Run Code Online (Sandbox Code Playgroud)
通常情况下,他们会这样使用:
with DB1() as db1, DB2() as db2:
db1.do_stuff()
db2.do_other_stuff()
Run Code Online (Sandbox Code Playgroud)
无论发生什么,db1并db2都将运行自己的__exit__功能,并清理连接,同花顺等
当我把所有这些都放在课堂上时,我该怎么做?这是正确的吗?这显然是不正确的,正如评论中所指出的那样,上下文管理器db1并db2在块的末尾运行.
class MyApp(object):
def __enter__(self):
with DB1() as self.db1, DB2() as self.db2:
return self
def __exit__(self, type, value, traceback):
self.db1.__exit__(self, type, value, traceback)
self.db2.__exit__(self, type, value, traceback)
Run Code Online (Sandbox Code Playgroud)
我甚至考虑过做这样的事情:这看起来是个好主意,实际上(经过一些清理):
class MyApp(object):
def __init__(self):
self.db1 = DB1()
self.db2 = DB2()
def __enter__(self):
self.db1.__enter__()
self.db2.__enter__()
return …Run Code Online (Sandbox Code Playgroud) 我最近一直在研究Python的contextmanager(更具体地说,Python 3的contextlib或其向后移植的contextlib2),我想知道将它们编写为类与函数相比有何优点/缺点?
它们似乎都以相同的方式运行并以相同的方式处理异常。有很多很酷的实用程序,例如 ExitStack(),但这些实用程序似乎可以在编写为类或函数的上下文管理器中实现。因此,我正在努力寻找一个很好的理由来解释为什么人们想要将上下文管理器详细地编写为一个类,而它们可以被编写为一个函数并且只需使用 contextmanager 装饰器即可。
这是我写的一个简单的例子,展示了两者做同样的事情:
# !/usr/bin/python -u
# encoding: utf-8
from contextlib import contextmanager
# Function-based
@contextmanager
def func_custom_open(filename, mode):
try:
f = open(filename, mode)
yield f
except Exception as e:
print(e)
finally:
f.close()
# Class-based
class class_custom_open(object):
def __init__(self, filename, mode):
self.f = open(filename, mode)
def __enter__(self):
return self.f
def __exit__(self, type, value, traceback):
self.f.close()
if __name__ == '__main__':
# Function-based
with func_custom_open('holafile_func.txt', 'w') as func_f:
func_f.write('hola func!')
# Class-based
with class_custom_open('holafile_class.txt', 'w') as class_f:
class_f.write('hola …Run Code Online (Sandbox Code Playgroud)