在上下文管理器 (with) 和异常处理程序中使用 as 分配给成员

Assigning to a member with `as` in context-manager (with) and exception handler

首先,如果我没有使用正确的名称,我想道歉,我是 Python 的新手。

在玩游戏时我发现您可以在 with 语句的 as 部分分配给 class 成员:

from contextlib import contextmanager

@contextmanager
def func(val):
    yield val*2

class Foo:
    def __init__(self):
        self.val = "Placeholder"

    def bar(self):
        with func(333) as self.val:
            print("Got", self.val)


if __name__ == "__main__":
    f = Foo()
    print("Before:", f.val)
    f.bar()
    print("After:", f.val)

输出:

Before: Placeholder
Got 666
After: 666

但是,分配给 except 中的成员会出现语法错误:

class Foo:
    def __init__(self):
        self.err = None

    def bar(self):
        try:
            os.remove(path)
        except FileNotFoundError as self.err:
            print("Couldn't remove", path)

输出:

except FileNotFoundError as self.err:                                      
                                ^

SyntaxError: invalid syntax

由于搜索 as 是徒劳的,我无法找到任何参考资料,我的问题是:

  1. with 语句的 as 部分分配给成员的定义是否明确?
  2. 如果是,为什么异常处理不允许?

编辑:我想关于 import...

可以问类似的问题

except clause, as can only assign to an identifier. In a with clause中,as可以分配给任意目标。

try1_stmt ::=  "try" ":" suite
           ("except" [expression ["as" identifier]] ":" suite)+
           ["else" ":" suite]
           ["finally" ":" suite]

with_item ::=  expression ["as" target]

一个target是一个标识符(foo),一个属性(foo.bar),一个切片(foo[:bar]),一个订阅(foo[bar] ), 上面的 list/tuple (foo, bar) 或上面的 splat (*foo).


异常会在其异常处理程序后自动清除。在处理程序后使用名称表明它已被删除:

>>> a = 1
>>> try:
...     1/0
... except ZeroDivisionError as a:
...     pass
... print(a)
NameError: name 'a' is not defined

这避免了异常、引发异常的框架和绑定异常的名称之间不必要的引用循环。

直接绑定到另一个名称空间需要选择以下两种情况之一:

  • 属性在处理程序之后被删除。这意味着物体的外观不一致。
  • 处理程序后未删除该属性。这意味着除非手动清除,否则框架将无限期存在。

这两种变体都需要在处理程序之外显式处理异常。此外,它们很容易意外触发需要在其他地方进行显式处理的情况。