【发布时间】:2021-11-09 13:33:10
【问题描述】:
我对 python3 中的类型注释感到有些困惑,特别是对于生成生成类型的生成器函数。我认为,具体来说,我的困惑源于typing.Type 的文档。这是我的代码sn-p:
from collections import UserList
UserType = TypeVar('UserType')
def TypeSequence(usertype: Type[UserType]) -> Type[Sequence[UserType]]:
class Result(UserList):
... # Cut out the implementation for brevity's sake
return Result
生成的“TypeSequence”正在做一些类型检查,以便只生成可序列化的数据结构,这对这个问题并不重要。关键是你应该能够做这样的事情:
MyIntSequence = TypeSequence(int)
MyIntSequence((1, 2, 3)) -> [1, 2, 3] with type Sequence[Int]
MyTupleSequence = TypeSequence(tuple)
MyTupleSequence(((1, 2), (3, 4))) -> [(1, 2), (3, 4)] with type Sequence[tuple]
我的问题:我提供的类型注释是否正确?
我的疑问主要源于 PyCharm 未能提供由我的自定义生成器函数生成的类型。可能是 PyCharm 的问题,但我对此表示怀疑,因为它非常适用于标准库,标准库几乎使用同样复杂的类型注释。
类型推断似乎失败的简单示例:
请注意这与此列表版本的对比:
我也收到很多关于“TypeSequence”实际作用的问题。我编辑了该实现以提供更简短的中肯帖子,但这里是完整的实现。它执行一些类型强制和类型检查:
from collections import UserList
from typing import (Optional, Any, Sequence, Callable, Hashable, Dict, Mapping, Type, TypeVar,
)
UserType = TypeVar('UserType')
def TypeSequence(usertype: Type[UserType]) -> Type[Sequence[UserType]]:
class Result(UserList):
def __init__(self, *args):
from collections import Iterable
if len(args) == 0:
super(Result, self).__init__()
elif len(args) == 1:
if not isinstance(args[0], Iterable):
raise ValueError("Not a iterable")
if issubclass(usertype, tuple) and hasattr(usertype, "_fields"):
if any(not isinstance(x, Iterable) for x in args[0]):
raise ValueError("Invalid initializer for named tuple")
if len(args[0]) != len(usertype._fields):
raise ValueError(f"Not enough values to initialize {usertype}")
seq = (usertype(*x) for x in args[0])
else:
seq = (usertype(x) for x in args[0])
super(Result, self).__init__(seq)
Result.__name__ = f"TypeSequence[{usertype.__name__}]"
return Result
【问题讨论】:
-
什么是
UserList?它是未定义的。 -
你能举一个类型推断失败的例子吗?注释看起来不错,虽然我没有看到函数的意义。看起来它并没有比
list做的更多。 -
TypeSequence实际上是做什么的?它似乎与生成器函数的 Python 定义无关,生成器函数使用yield生成generator类型的值。 -
@PKCakeout 是否需要使用
UserList,而不仅仅是返回list的子类?那么你的返回类型可能只是Type[List[UserType]]。
标签: python python-typing