tMC*_*tMC 23 python exception with-statement contextmanager python-2.7
__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):
if all((e_typ, e_val, trcbak)):
raise e_typ, e_val, trcbak
# __exit__ code
with TstContx() as tc:
if hasattr(tc, 'init_exc'): raise tc.init_exc
# code in context
Run Code Online (Sandbox Code Playgroud)
在后面看来,上下文管理器可能不是最好的设计决策
Lau*_*low 20
像这样:
import sys
class Context(object):
def __enter__(self):
try:
raise Exception("Oops in __enter__")
except:
# Swallow exception if __exit__ returns a True value
if self.__exit__(*sys.exc_info()):
pass
else:
raise
def __exit__(self, e_typ, e_val, trcbak):
print "Now it's running"
with Context():
pass
Run Code Online (Sandbox Code Playgroud)
为了让程序继续以愉快的方式继续而不执行上下文块,您需要检查上下文块中的上下文对象,并且只有__enter__成功时才执行重要的操作.
class Context(object):
def __init__(self):
self.enter_ok = True
def __enter__(self):
try:
raise Exception("Oops in __enter__")
except:
if self.__exit__(*sys.exc_info()):
self.enter_ok = False
else:
raise
return self
def __exit__(self, e_typ, e_val, trcbak):
print "Now this runs twice"
return True
with Context() as c:
if c.enter_ok:
print "Only runs if enter succeeded"
print "Execution continues"
Run Code Online (Sandbox Code Playgroud)
据我所知,你不能完全跳过with-block.请注意,此上下文现在吞下了其中的所有异常.如果您不希望吞下例外,如果__enter__成功,检查self.enter_ok中__exit__和return False,如果它是True.
我建议您遵循 RAII(资源获取即初始化)并使用上下文的构造函数来执行可能失败的分配。然后你__enter__可以简单地返回 self ,它永远不会引发异常。如果您的构造函数失败,则可能会在进入 with 上下文之前引发异常。
class Foo:
def __init__(self):
print("init")
raise Exception("booh")
def __enter__(self):
print("enter")
return self
def __exit__(self, exc_type, exc_val, exc_tb):
print("exit")
return False
with Foo() as f:
print("within with")
Run Code Online (Sandbox Code Playgroud)
输出:
init
Traceback (most recent call last):
File "<input>", line 1, in <module>
...
raise Exception("booh")
Exception: booh
Run Code Online (Sandbox Code Playgroud)
编辑: 不幸的是,这种方法仍然允许用户创建“悬空”资源,如果他执行以下操作,这些资源将不会被清理:
foo = Foo() # this allocates resource without a with context.
raise ValueError("bla") # foo.__exit__() will never be called.
Run Code Online (Sandbox Code Playgroud)
我很好奇是否可以通过修改类的新实现或其他一些禁止在没有上下文的情况下实例化对象的Python魔法来解决这个问题。
| 归档时间: |
|
| 查看次数: |
15785 次 |
| 最近记录: |