1

我正在查看typeshed源代码,发现pathlib.pyi它执行以下操作:

_P = TypeVar('_P', bound=PurePath)

...

class PurePath(_PurePathBase): ...

我有一个类似的情况,基类从__new__(类似于Path)返回一个子类,因此类型注释也相似。但是,将bound关键字定义为下面定义的类会解析为NameError,因为名称尚未解析(正如我所预料的那样;由于typeshed来源而尝试)。

from abc import ABC
from typing import Type
from typing import TypeVar
from foo.interface import SomeInterface

_MT = TypeVar('_MT', bound=MyBaseClass)

class MyBaseClass(SomeInterface, ABC):
    def __new__(cls: Type[_MT], var: int = 0) -> _MT:
        if var == 1:
            return object.__new__(FirstSubClass)
        return object.__new__(cls)

class FirstSubClass(MyBaseClass): pass

如何typeshed摆脱这个?这对我的打字来说是完美的,否则我必须这样做:

_MT = TypeVar('_MT', covariant=True, bound=SomeInterface)

并且我所有的 linter 警告都满足("expected type _MT, got object instead")...

更好的匹配案例是输入工厂方法,因为我使用__new__的工厂方法类似于Path它的方式和描述here。不过,很高兴知道如何在不使用字符串的情况下typeshed完成此前向引用。bound

4

1 回答 1

0

In runtime Python code, you can use string literal types in the bound attribute to create a forward reference:

>>> _MT = TypeVar('_MT', bound='MyBaseClass')
>>> _MT.__bound__
ForwardRef('MyBaseClass')

As for why a non-string can be used in typeshed, it's because typeshed provides .pyi stub files, which are syntactically valid Python code, but are not meant to be executed, only to be examined by type checkers. There's little I could find on specifications for stub files, but it makes sense to assume that everything is implicitly a string literal. This seems to be implied from the mypy docs:

String literal types are never needed in # type: comments and stub files.

于 2021-05-23T16:55:38.063 回答