Python 打字:如何让 Type[C] 与 TypeVars 和泛型一起工作?

Posted

技术标签:

【中文标题】Python 打字:如何让 Type[C] 与 TypeVars 和泛型一起工作?【英文标题】:Python Typing: how to get Type[C] to work with TypeVars and Generics? 【发布时间】:2019-02-26 04:04:55 【问题描述】:

我试图弄清楚如何让 Python 泛型类型提示与 Type[C] 的构造函数参数配合得很好。考虑这个代码示例:

class Foo(object):
  fooval: str

  def __init__(self, val):
    self.fooval = val

class Bar(object):
  barval: str

  def __init__(self, val):
    self.barval = val

T = TypeVar('T', Foo, Bar)

class FooBarContainer(Generic[T]):
  child: T

  # Type[T] seems logical here, but that's not valid according to the docs
  def __init__(self, ctorable: Type[Union[Foo, Bar]], val):
    self.child = ctorable(val)

baz = FooBarContainer(Foo, val)
# This does not get flagged by type-checkers, but will obviously fail at runtime
failure = baz.child.barval

尝试使用 Type[T] 会导致类型检查器错误:

预期类型[T],得到类型[Foo]

所以这里的目标是弄清楚如何让 TypeVars 与 Type[C] 一起工作。这样静态分析就会知道,当我用特定的 Type[T] 调用特定的 func 时,我期望得到 T。我似乎在这里找不到任何可以帮助我的文档。

在处理函数时也会出现同样的问题。例如,这是有效的语法,但在输入方面显然无效:

def initor(thing_type: Type[Union[Foo, Bar]], val) -> T:
  return thing_type(val)

【问题讨论】:

【参考方案1】:

您能否澄清“Type[T] 在这里似乎合乎逻辑,但根据文档无效”是什么意思?

具体来说,您正在查看哪些文档?以下代码使用 mypy 0.630 按预期工作:

class FooBarContainer(Generic[T]):
  child: T

  def __init__(self, ctorable: Type[T], val) -> None:
    self.child = ctorable(val)

val = 3
baz = FooBarContainer(Foo, val)

# Mypy reports a `"Foo" has no attribute "barval"` error
failure = baz.child.barval  

如果文档暗示给ctorable 提供Type[T] 类型不起作用,则可能应该更新它们。

【讨论】:

感谢您的回复!我正在使用 PyCharm 的类型检查来分析这个,所以现在我想知道这是否是我的问题!我将不得不针对我的代码测试 mypy 并看看它是如何做的。这给了我一个很好的线索。我正在查看的文档在这里:docs.python.org/3/library/typing.html#typing.Type 我可能误读了这一行:Type 的唯一合法参数是类、类的联合和 Any。我不确定 TypeVar 在这里是否是一个有效值,而且 PyCharm 似乎无法理解 Type[T] 的事实给了我一个潜在的错误偏见。 @Zoinks -- 哦,这太尴尬了……我实际上是贡献文档特定部分的人 -- 我不确定我为什么要写这个。 Type[T] 可能在 2 年前确实没有被考虑(当时我写了文档的那部分);我也有可能完全忘记了类型变量。有点恼人的是,PEP 484 给出了完全不同的答案:似乎认为Type[T] 是合法的,但仅在注释类方法的第一个参数时... 无论如何,一旦我得到澄清,我会四处询问+发布更新评论。 哦,非常整洁!感谢您抽出宝贵的时间,谢谢。 @Zoinks -- 打字文档是updated now; PEP 484 可能需要更长的时间来更新,主要是因为必要的措辞更改需要更多的工作。

以上是关于Python 打字:如何让 Type[C] 与 TypeVars 和泛型一起工作?的主要内容,如果未能解决你的问题,请参考以下文章

如何让 Python 数据类 InitVar 字段与 typing.get_type_hints 一起使用,同时还使用注释?

打字稿:键入'字符串| undefined' 不能分配给 type 'string'

通用类型(T)与打字稿中的任何类型有啥区别

Into 和 From 接口:与打字的斗争。Type 的协方差

Python - 如何传递给类对象的函数参数类型(打字)

节点猫鼬打字稿如何输入 type: ObjectId, ref: 'User'