gpt4 book ai didi

python - 在 3.5 中键入 __exit__ 在运行时失败,但类型检查

转载 作者:太空狗 更新时间:2023-10-30 01:36:24 24 4
gpt4 key购买 nike

__exit__ 的正确类型签名是什么?我有以下内容:

from types import TracebackType
from typing import Optional, Type

class Foo:
def __enter__(self) -> 'Foo':
return self

def __exit__(self, exc_type: Optional[Type[BaseException]],
exc_value: Optional[BaseException],
traceback: Optional[TracebackType]) -> bool:
return False

在最近的 mypy (0.560) 上,它使用 --strict 进行类型检查(我对这个签名有一定的信心,因为我从类型库的内部偷走了它)。

当此脚本使用 python 3.6 运行时,正如预期的那样没有任何反应。但是当使用 3.5.2 运行时,我们得到一个异常:

Traceback (most recent call last):
File "/home/student/mypy_test/test.py", line 4, in <module>
class Foo: #(ContextManager['Foo']):
File "/home/student/mypy_test/test.py", line 8, in Foo
def __exit__(self, exc_type: Optional[Type[BaseException]],
File "/usr/lib/python3.5/typing.py", line 649, in __getitem__
return Union[arg, type(None)]
File "/usr/lib/python3.5/typing.py", line 552, in __getitem__
dict(self.__dict__), parameters, _root=True)
File "/usr/lib/python3.5/typing.py", line 512, in __new__
for t2 in all_params - {t1} if not isinstance(t2, TypeVar)):
File "/usr/lib/python3.5/typing.py", line 512, in <genexpr>
for t2 in all_params - {t1} if not isinstance(t2, TypeVar)):
File "/usr/lib/python3.5/typing.py", line 1077, in __subclasscheck__
if super().__subclasscheck__(cls):
File "/home/student/.local/share/virtualenvs/sf_cs328-crowdsourced-QAuuIxFA/lib/python3.5/abc.py", line 225, in __subclasscheck__
for scls in cls.__subclasses__():
TypeError: descriptor '__subclasses__' of 'type' object needs an argument

如果去掉参数直到异常消失,我们发现问题类型是第一个:exc_type: Optional[Type[BaseException]]

注意:如果类型签名不匹配(使用 mypy 运行时),要让它发出提示,您需要将 class Foo: 更改为 class Foo(ContextManager['Foo'])。我没有在代码片段中这样做,因为 Python 3.5.2 中的 typing 缺少 CoroutineAwaitableContextManager 等(这是旧发行版的 LTS 版本中的版本)。我在这里写了一个解决方法:https://stackoverflow.com/a/49952293/568785 .所以我想,完整的可重现示例是:

# Workaround for ContextManager missing in 3.5.2 typing
from typing import Any, TypeVar, TYPE_CHECKING
try:
from typing import ContextManager
except ImportError:
class _ContextManager:
def __getitem__(self, index: Any) -> None:
return type(object())

if not TYPE_CHECKING:
ContextManager = _ContextManager()

# The actual issue:
from types import TracebackType
from typing import Optional, Type

class Foo:
def __enter__(self) -> 'Foo':
return self

def __exit__(self, exc_type: Optional[Type[BaseException]],
exc_value: Optional[BaseException],
traceback: Optional[TracebackType]) -> bool:
return False

我已经验证不继承 ContextManager 在 Python 3.5.2 中运行仍然会产生错误(所以这个异常不是这个 hack 的产物,它是 3.5.2 的产物运行时的类型库不喜欢 __exit__ 的签名)。

据推测,这是 Python 3.5 的 typing 库中的另一个错误。有解决这个问题的明智方法吗?

最佳答案

我现在使用的一个丑陋解决方法是使用TYPE_CHECKING 来确定我是否应该伪造类型:

from typing import Type, TYPE_CHECKING

if TYPE_CHECKING:
BaseExceptionType = Type[BaseException]
else:
BaseExceptionType = bool # don't care, as long is it doesn't error

然后你可以这样做:

def __exit__(self, exc_type: Optional[BaseExceptionType],
exc_value: Optional[BaseException],
traceback: Optional[TracebackType]) -> bool:
return False

已针对 Python 3.5.2 和 mypy 0.560 进行验证。

这当然会破坏任何 RTTI,但 AFAIK RTTI 是 PEP 的一部分,直到 3.6 或 3.7 才(实验性地)登陆。不过,这显然会破坏 typing.get_type_hints()

关于python - 在 3.5 中键入 __exit__ 在运行时失败,但类型检查,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49959656/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com