Can I use __qualname__ in a Python type hint with postponed annotation evaluation?

孤街浪徒 提交于 2020-01-24 19:55:06

问题


I like using __qualname__ for the return-type annotation of factory-style class methods, because it doesn't hardcode the classname and therefore keeps working subclasses (cf. this answer).

class Foo:
    @classmethod
    def make(cls) -> __qualname__:
        return cls()

Currently this seems to work fine, but I am not sure whether this will still be possible with the postponed evaluation of annotations (PEP 563): the PEP says that

Annotations can only use names present in the module scope as postponed evaluation using local names is not reliable (with the sole exception of class-level names resolved by typing.get_type_hints()).

The PEP also says:

The get_type_hints() function automatically resolves the correct value of globalns for functions and classes. It also automatically provides the correct localns for classes.

However, the following code

from __future__ import annotations

import typing

class Foo():
    @classmethod
    def make(cls) -> __qualname__:
        return cls()

print(typing.get_type_hints(Foo.make))

fails with

  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

Commenting the __future__ import makes the code work again, in that case it outputs

{'return': <class '__main__.Foo'>}

as expected.

Is my use case __qualname__ supported (which would mean that get_type_hints is buggy), or is this approach not possible with PEP 563?


回答1:


Foo.make doesn't always return an instance of Foo (which is what __qualname__ expands to). It returns an instance of the class it receives as an argument, which isn't necessarily Foo. Consider:

>>> class Foo:
...     @classmethod
...     def make(cls):
...         return cls()
...
>>> class Bar(Foo):
...     pass
...
>>> type(Bar.make())
<class '__main__.Bar'>

The correct type hint would be a type variable:

T = TypeVar("T", bound="Foo")

class Foo:
    @classmethod
    def make(cls: Type[T]) -> T:
        return cls()


来源:https://stackoverflow.com/questions/59375599/can-i-use-qualname-in-a-python-type-hint-with-postponed-annotation-evaluatio

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!