Python内置的__exit__参数类型有哪些?

42

类具有可定义的函数__exit__,允许实现上下文管理器。

它需要以下必需参数:

def __exit__(self, exc_type, exc_val, exc_tb):

但是我找不到它们是什么以及它们的类型的明确定义。

这是我最好的猜测,它们是什么以及为什么这样,但我并不完全确定:

def __exit__(self, exc_type: Exception, exc_val: TracebackException, exc_tb: TracebackType):

exc_type

Python定义了一个TracebackException类,它接受一个exc_type参数,该参数在构造函数中上下文地与issubclassSyntaxError一起使用,这表明exc_type确实是某种Exception,而SyntaxError则继承自exc_type

exc_val

此外,在那个TracebackException类中,有一个exc_value参数,对应于我们的exc_val,似乎具有各种属性,如__cause____context__和其他属性,所有这些属性都在TracebackType本身中定义。这让我想到该参数本身就是TracebackException的实例。

exc_tb

Python定义了一个walk_tb函数,它使用exc_tb作为参数(从docs.python.org手动跟踪),这个对象似乎具有tb_frametb_linenotb_next属性,可以追溯到typeshed库中的TracebackType类。

你有什么想法?

2个回答

51

exc_type 是异常的类。 exc_val 是异常实例。 exc_tb 是一个 traceback 对象,其中在 types.TracebackType 中有一个引用。

通常情况下应该是这样的

  • type(exc_val) is exc_type
  • exc_val.__traceback__ is exc_tb

请注意,当在上下文管理器中的代码没有引发异常时,仍会调用 __exit__,并且参数将为 (None, None, None),因此所有三个参数都应该被注释为可选项。

然后,对它正确的注释应该看起来像这样:

def __exit__(self, exctype: Optional[Type[BaseException]],
             excinst: Optional[BaseException],
             exctb: Optional[TracebackType]) -> bool: ...

当你看到这个API有三个参数时,你可能会想为什么其中两个可以从异常实例本身中轻松确定。但并不总是这样,因为在早期版本的Python中,你可以将字符串作为异常抛出,而异常的__traceback__属性在Python 2.5之前就不存在了。在Python 2.7中,你仍然可以抛出旧式类作为异常!


1
我们从哪里导入TrackbackType? - Mentos1386
3
types模块导入它,不要与typing模块混淆。 - Gigi Bayte 2
1
exit 的返回类型注释应该是 Optional[bool] 吗?https://www.python.org/dev/peps/pep-0343/#id38 - Laurenz
@Laurenz 在 https://github.com/python/typeshed/blob/095464874accef1cc5303f325ccabe88756bcd8b/stdlib/2and3/contextlib.pyi#L70 中使用了 bool。我猜返回 None 和 False 没有实际区别,但由于鸭子类型的原因,它可以正常工作。 - wim
如果你不想处理异常,那么 def __exit__(self, *exc: List[Any]) -> None: 似乎可以完成工作(Mypy 不再抱怨)。 - starblue

5
mypy issue 4885中,Jelle Zijlstra提供了__exit__的标准签名。
适应你的参数名称和适当的导入:
from typing import Optional, Type
from types import TracebackType

def __exit__(
    self,
    exc_type: Optional[Type[BaseException]],
    exc_val: Optional[BaseException],
    exc_tb: Optional[TracebackType],
) -> bool:
   ...

如果您想禁止上下文中引发的异常,则应从__exit__返回True,在所有其他情况下返回False

1
这不就是wim的回答的重复吗? - Daniel Walker

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接