python一个try块后接一个或多个finally块_Python *与*语句完全等同于一个try – (除了) – finally块?...
我會放棄提及的范圍,因為它真的不是很相關.
with EXPR as VAR:
BLOCK
翻譯成
mgr = (EXPR)
exit = type(mgr).__exit__ # Not calling it yet
value = type(mgr).__enter__(mgr)
exc = True
try:
try:
VAR = value # Only if "as VAR" is present
BLOCK
except:
# The exceptional case is handled here
exc = False
if not exit(mgr, *sys.exc_info()):
raise
# The exception is swallowed if exit() returns true
finally:
# The normal and non-local-goto cases are handled here
if exc:
exit(mgr, None, None, None)
如你所見,鍵入(mgr).__ enter__被調用,如你所料,但不是在嘗試.
類型(mgr).__ exit__在退出時調用.唯一的區別是當有異常時,如果沒有退出(mgr,* sys.exc_info())路徑.這使得能夠內省和沉默錯誤,而不像finally子句可以做什么.
contextmanager并不會使這一點復雜化.只是:
def contextmanager(func):
@wraps(func)
def helper(*args, **kwds):
return _GeneratorContextManager(func, *args, **kwds)
return helper
然后看看有關的課程:
class _GeneratorContextManager(ContextDecorator):
def __init__(self, func, *args, **kwds):
self.gen = func(*args, **kwds)
def __enter__(self):
try:
return next(self.gen)
except StopIteration:
raise RuntimeError("generator didn't yield") from None
def __exit__(self, type, value, traceback):
if type is None:
try:
next(self.gen)
except StopIteration:
return
else:
raise RuntimeError("generator didn't stop")
else:
if value is None:
value = type()
try:
self.gen.throw(type, value, traceback)
raise RuntimeError("generator didn't stop after throw()")
except StopIteration as exc:
return exc is not value
except:
if sys.exc_info()[1] is not value:
raise
不重要的代碼已經消失.
首先要注意的是,如果有多個收益率,這個代碼將會出錯.
這并不明顯地影響控制流程.
考慮__enter__.
try:
return next(self.gen)
except StopIteration:
raise RuntimeError("generator didn't yield") from None
如果上下文管理器寫得很好,那永遠不會從預期的中斷.
一個區別是,如果生成器拋出StopIteration,將產生一個不同的錯誤(RuntimeError).這意味著,如果您正在運行完全任意的代碼,則該行為與正常行為不完全相同.
考慮一個非錯誤的__exit__:
if type is None:
try:
next(self.gen)
except StopIteration:
return
else:
raise RuntimeError("generator didn't stop")
唯一的區別就像以前一樣.如果你的代碼拋出StopIteration,它會影響生成器,因此contextmanager裝飾器會誤解它.
這意味著:
from contextlib import contextmanager
@contextmanager
def with_cleanup(func):
try:
yield
finally:
func()
def good_cleanup():
print("cleaning")
with with_cleanup(good_cleanup):
print("doing")
1/0
#>>> doing
#>>> cleaning
#>>> Traceback (most recent call last):
#>>> File "", line 15, in
#>>> ZeroDivisionError: division by zero
def bad_cleanup():
print("cleaning")
raise StopIteration
with with_cleanup(bad_cleanup):
print("doing")
1/0
#>>> doing
#>>> cleaning
哪個不太重要,但可以.
最后:
else:
if value is None:
value = type()
try:
self.gen.throw(type, value, traceback)
raise RuntimeError("generator didn't stop after throw()")
except StopIteration as exc:
return exc is not value
except:
if sys.exc_info()[1] is not value:
raise
這提出了與StopIteration相同的問題,但有趣的是注意到最后一部分.
if sys.exc_info()[1] is not value:
raise
這意味著如果未處理異常,則追溯將不會更改.如果它被處理但存在新的追溯,那將被提升.
這完全符合規格.
TL; DR
與實際上比實際上稍微強大一點…終于可以內省和沉默錯誤.>請注意StopIteration,否則您可以使用@contextmanager創建上下文管理器.
總結
以上是生活随笔為你收集整理的python一个try块后接一个或多个finally块_Python *与*语句完全等同于一个try – (除了) – finally块?...的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python中包的循环导入_具有继承的包
- 下一篇: 代码python文艺的_Python小解