引用泛型类型的类属性
Posted
技术标签:
【中文标题】引用泛型类型的类属性【英文标题】:Referring to class attributes of a generic type 【发布时间】:2019-10-27 04:24:59 【问题描述】:我有一个抽象基类,它定义了几个本身就是类型的类属性(即嵌套类型);这些属性在从抽象类继承的具体派生类中被覆盖。具体派生类与其他几个被类型注释为泛型的类一起使用,其中类型参数具有必须从抽象类派生的类型约束。我希望这些其他类(泛型)引用具体类的类属性(嵌套类型)。下面的例子应该证明这个想法:
import typing
class Base:
A: typing.Type[Base]
class One(Base):
class A(Base): # overrides Base.A
pass
class Two(Base):
class A(One): # overrides Base.A
pass
T = typing.TypeVar('T', bound=Base)
class Foo(typing.Generic[T]): # the generic
def foo(self, a: typing.Type[T.A]) -> T: # <-- here, see T.A
...
f: Foo[Two] = Foo()
f.foo(Two.A) # line 22 is here
MyPy v0.701 在第 22 行报错:
“Foo”的“foo”的参数 1 具有不兼容的类型“Type[A]”;预期“类型[Two]”
MyPy 似乎忽略了T.A
的属性引用。我如何理解我试图通过属性.A
引用可用的类型?该属性保证可用,因为类型变量T
被限制为Base
,它具有A
。请注意,扩展泛型类型集不是一种选择;我可以详细说明这一点,但解释过于针对我的应用程序。
更新:带有--new-semantic-analyzer
的 MyPy v0.711 会产生更易于理解的错误消息:
名称“T.A”未定义
【问题讨论】:
请注意,您对 f.foo 的调用不正确,即使不是出于 mypy 所述的原因。你传入一个 Type[A] 的实例,但你的注解只需要一个 A 的实例。 foo 的主体实际上是...,还是您有可能将 T.A 限制为 T 的实现? 是的,确实,我搞砸了这个例子,同时剥离了与我的应用程序无关的细节,对不起。foo
的主体比较复杂,这里就不展示了;它需要在派生类中定义的 A 的特定实现。
【参考方案1】:
我不确定这是否有帮助,但如果你参数化绑定到 Base 的参数,它会起作用:
class Base:
A: typing.Type['Base']
class One(Base):
class A(Base): # overrides Base.A
pass
class Two(Base):
class A(One): # overrides Base.A
pass
T = typing.TypeVar('T', bound='Base')
A = typing.TypeVar('A', bound='Base')
class Foo(typing.Generic[T, A]): # the generic
def foo(self, a: typing.Type[A]) -> T: # <-- here, see T.A
pass
f: Foo[Two, Two.A] = Foo()
f.foo(Two.A) # line 22 is here
【讨论】:
谢谢。不幸的是,正如我在问题的最后提到的那样,添加一个新的类型参数是非常不可取的,因为它会使面向用户的 API 变得不必要地复杂。到那时,我预计用户可能会想只用# type: ignore
粘贴代码,而不是处理类型参数。或许我应该把我的代码全部发布在这里进行深入审查?
我很难过。我认为这可能与协方差有关,但将该属性添加到 TypeVar 似乎没有帮助。最奇怪的是错误消息 expected "Type[Two]"
就像它只是忽略了 Type 参数的 .A
部分。这感觉就像 MyPy 中的词法分析器错误。以上是关于引用泛型类型的类属性的主要内容,如果未能解决你的问题,请参考以下文章