【发布时间】:2019-12-17 13:44:56
【问题描述】:
我喜欢将__qualname__ 用于工厂式类方法的返回类型注释,因为它不会对类名进行硬编码,因此可以保持工作子类(参见this answer)。
class Foo:
@classmethod
def make(cls) -> __qualname__:
return cls()
目前这似乎工作正常,但我不确定这是否仍然可以通过延迟评估注释 (PEP 563):PEP says 那
注释只能使用模块范围内的名称,因为使用本地名称的延迟评估不可靠(
typing.get_type_hints()解析的类级名称除外)。
PEP 还有says:
get_type_hints()函数自动为函数和类解析globalns的正确值。它还会自动为类提供正确的localns。
但是,下面的代码
from __future__ import annotations
import typing
class Foo():
@classmethod
def make(cls) -> __qualname__:
return cls()
print(typing.get_type_hints(Foo.make))
失败
File "qualname_test.py", line 11, in <module>
print(typing.get_type_hints(Foo.make))
File "/var/local/conda/envs/py37/lib/python3.7/typing.py", line 1004, in get_type_hints
value = _eval_type(value, globalns, localns)
File "/var/local/conda/envs/py37/lib/python3.7/typing.py", line 263, in _eval_type
return t._evaluate(globalns, localns)
File "/var/local/conda/envs/py37/lib/python3.7/typing.py", line 467, in _evaluate
eval(self.__forward_code__, globalns, localns),
File "<string>", line 1, in <module>
NameError: name '__qualname__' is not defined
注释 __future__ 导入会使代码再次工作,在这种情况下它会输出
{'return': <class '__main__.Foo'>}
正如预期的那样。
我的用例 __qualname__ 是否受支持(这意味着 get_type_hints 有问题),还是 PEP 563 无法使用这种方法?
【问题讨论】:
-
您对
__qualname__的使用不正确。考虑class Bar(Foo): pass。Bar.make()不返回Foo的实例;它返回一个Bar的实例。 -
正确的类型提示可能是
TypeVar:def make(cls: Type[T]) -> T。 -
@chepner:你说得对,我没有想到这一点。但是,随着延迟评估应该开始起作用,对吗?因为那么
Bar.make的注解应该在Bar的上下文中进行评估,其中__qualname__指的是Bar。 -
FWIW:虽然
mypy目前不支持__qualname__,但mypy/#6473 存在问题。它已被接受为描述错误并正在处理中。我不知道get_type_hints中断是否是一个错误——它似乎对所有类级属性(包括类型和别名)都中断了,但还没有错误报告。