Python中的受限泛型类型提示

Python中的受限泛型类型提示,python,type-hinting,typing,Python,Type Hinting,Typing,我想创建一个类似于这里的工厂方法 class A: ... class B(A): def f(self): ... class C: ... def factory(cls): return cls() 但我想添加一些类型提示,其中包含两个要求: 只有A的子类才允许作为factory的参数 当传递B时,会正确检测到factory(B)是B的实例,即factory(B).f()是允许的,而factory(A).f()不是 尝试1 使用键

我想创建一个类似于这里的工厂方法

class A:
    ...

class B(A):
    def f(self):
        ...

class C:
    ...

def factory(cls):
    return cls()
但我想添加一些类型提示,其中包含两个要求:

  • 只有
    A
    的子类才允许作为
    factory
    的参数
  • 当传递
    B
    时,会正确检测到
    factory(B)
    B
    的实例,即
    factory(B).f()
    是允许的,而
    factory(A).f()
    不是
尝试1 使用
键入模块中的
键入

from typing import Type

class A:
    ...

class B(A):
    def f(self):
        ...

class C:
    ...

def factory(cls: Type[A]):
    return cls()

factory(A)  # Ok
factory(B)  # Ok
factory(C)  # Fail
factory(A).f()  # Fail
factory(B).f()  # Fail -- Wrong!
这个函数正确地检测到
C
不应该作为
factory
的参数传递。但是,类型检查器不允许使用工厂(B).f()

尝试2 使用
TypeVar

from typing import TypeVar, Type
T = TypeVar('T')

class A:
    ...

class B(A):
    def f(self):
        ...

class C:
    ...

def factory(cls: Type[T]) -> T:
    return cls()

factory(A)  # Ok
factory(B)  # Ok
factory(C)  # Ok -- Wrong!
factory(A).f()  # Fail
factory(B).f()  # Ok
可以很好地推断,
factory(B).f()
是好的,而
factory(A).f()
不是。然而,泛型是没有限制的,即工厂(C)也是可以的

尝试3 将约束添加到
T

from typing import TypeVar, Type

class A:
    ...

class B(A):
    def f(self):
        ...

class D(A):
    ...

class C:
    ...

T = TypeVar('T', A)
def factory(cls: Type[T]) -> T:
    return cls()


factory(A)  # Ok
factory(B)  # Ok
factory(C)  # Fail
factory(A).f()  # Fail
factory(B).f()  # Ok
这看起来很有希望,至少PyCharm能够正确处理所有情况。但是对于实际应用来说,这个解决方案实际上是最糟糕的-
不允许单个约束
出现错误,尽管还不清楚原因。在PEP 484中,只有一句简短的话说“应该至少有两个约束条件,如果有的话;不允许指定单个约束。”

有什么好的解决办法吗?我只想添加一个'dummy'类
\u a
,一个
a
的空白子类,并将其作为另一个约束条件来使用类似的内容

_A = NewType('_A', A)
T = TypeVar('T', A, _A)
def factory(cls: Type[T]) -> T:
    return cls()
但是我并不认为这是一个好的解决方案。


提前谢谢你

类型变量
绑定
一起使用似乎有效:

from typing import Type, TypeVar

class A:
    ...

class B(A):
    def f(self):
        ...

class C:
    ...

AnyA = TypeVar("AnyA", bound=A)

def factory(cls: Type[AnyA]) -> AnyA:
    return cls()


factory(A).f()  # error: "A" has no attribute "f"
factory(B).f()  # ok!
factory(C)      # error: Value of type variable "AnyA" of "factory" cannot be "C"

TypeVar
绑定一起使用似乎可以:

from typing import Type, TypeVar

class A:
    ...

class B(A):
    def f(self):
        ...

class C:
    ...

AnyA = TypeVar("AnyA", bound=A)

def factory(cls: Type[AnyA]) -> AnyA:
    return cls()


factory(A).f()  # error: "A" has no attribute "f"
factory(B).f()  # ok!
factory(C)      # error: Value of type variable "AnyA" of "factory" cannot be "C"
说:

…类型变量可以使用
bound=
指定上限。这意味着被类型变量替换(显式或隐式)的实际类型必须是边界类型的子类

这看起来和你想要的一模一样,所以你可以写:

T = TypeVar('T', bound=A)
说:

…类型变量可以使用
bound=
指定上限。这意味着被类型变量替换(显式或隐式)的实际类型必须是边界类型的子类

这看起来和你想要的一模一样,所以你可以写:

T = TypeVar('T', bound=A)

哦,当然。。我完全想念它。非常感谢。哦,当然。。我完全想念它。非常感谢。