Python中with语句的等效try语句是什么?

时间:2019-12-13 12:26:22

标签: python try-catch with-statement

在阅读了Python语言文档的with statement section之后,我想知道声明以下Python代码是否正确:

with EXPRESSION as TARGET:
    SUITE

与此等效:

try:
    manager = (EXPRESSION)
    value = manager.__enter__()
    TARGET = value  # only if `as TARGET` is present in the with statement
    SUITE
except:
    import sys
    if not manager.__exit__(*sys.exc_info()):
        raise
else:
    manager.__exit__(None, None, None)

编辑

Guido van Rossum本人在PEP 343中给出了正确的等效Python代码(真正的CPython实现在C语言中):

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)

自Python 3.6以来,这已经发生了一些变化:现在__enter__函数之前(参见https://bugs.python.org/issue27100)先于{em>加载了__exit__函数。

>

所以我等效的Python代码有三个缺陷:

  1. 应该在调用__enter__函数之前先加载__exit____enter__函数。
  2. __enter__函数应在try语句之外调用(参见语言文档中第4点的注释)。
  3. else子句应该是finally子句,以处理存在非本地goto语句(breakcontinue,{{1 }}})。

但是我不明白为什么PEP 343中的等效Python代码将return子句放在外部suite语句而不是内部finally语句中? / strong>

1 个答案:

答案 0 :(得分:1)

PEP 343的另一作者尼克·科格兰(Nick Coghlan)在Python bug tracker上回答:

  

这与历史时机有关:PEP 343是在   当try / finally和try / except分别为try / except / finally时   仍然是不同的陈述。

     

但是, 也接受并实现了针对Python 2.5的PEP 341,   允许使用现代的try / except / final形式:   https://docs.python.org/dev/whatsnew/2.5.html#pep-341-unified-try-except-finally

因此,try语句的现代with语句等效的Python代码是这样的:

manager = (EXPRESSION)
enter = type(manager).__enter__
exit = type(manager).__exit__
value = enter(manager)
hit_except = False

try:
    TARGET = value  # only if `as TARGET` is present in the with statement
    SUITE
except:
    import sys
    hit_except = True
    if not exit(manager, *sys.exc_info()):
        raise
finally:
    if not hit_except:
        exit(manager, None, None, None)