Python3 类型生成函数的类型注释
Python3 type annotations for type generating function
我对 python3 中的类型注释有点困惑,特别是对于吐出生成类型的生成器函数。我认为,具体来说,我的困惑源于 typing.Type
的文档。这是我的代码片段:
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”的实际作用的问题。我对该实现进行了编辑,使其更简洁 post,但这里是完整的实现。它执行一些类型强制和类型检查:
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
TLDR:对于要实例化的任何类型,使用 Callable
而不是 Type
。具体来说,明确 return 类型签名。
def TypeSequence(
usertype: Type[UserType]
) -> Callable[[Iterable[UserType]], Sequence[UserType]]
...
A Type[Sequence[UserType]]
无法实例化,因为 Sequence
是抽象类型。 mypy
将实例化标记为无效:
XSeq = TypeSequence(X)
x_seq = XSeq([X()]) # error: Too many arguments for "Sequence"
为了类型正确,请将 return 类型注释为 List
或 UserList
。
def TypeSequence(usertype: Type[UserType]) -> Type[UserList[UserType]]:
...
除了类型正确性之外,请注意 PyCharm 通常无法理解复杂的 Type
关系。揭示函数的类型表明 Type[UserList[UserType]]
被简化为 Type[UserList]
.
使用 Callable
代替允许表达复杂类型实例化。可以定义精确的签名,包括 Sequence
而不是 UserList
:
def TypeSequence(usertype: Type[UserType]) -> Callable[[Iterable[UserType]], Sequence[UserType]]:
...
我对 python3 中的类型注释有点困惑,特别是对于吐出生成类型的生成器函数。我认为,具体来说,我的困惑源于 typing.Type
的文档。这是我的代码片段:
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”的实际作用的问题。我对该实现进行了编辑,使其更简洁 post,但这里是完整的实现。它执行一些类型强制和类型检查:
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
TLDR:对于要实例化的任何类型,使用 Callable
而不是 Type
。具体来说,明确 return 类型签名。
def TypeSequence(
usertype: Type[UserType]
) -> Callable[[Iterable[UserType]], Sequence[UserType]]
...
A Type[Sequence[UserType]]
无法实例化,因为 Sequence
是抽象类型。 mypy
将实例化标记为无效:
XSeq = TypeSequence(X)
x_seq = XSeq([X()]) # error: Too many arguments for "Sequence"
为了类型正确,请将 return 类型注释为 List
或 UserList
。
def TypeSequence(usertype: Type[UserType]) -> Type[UserList[UserType]]:
...
除了类型正确性之外,请注意 PyCharm 通常无法理解复杂的 Type
关系。揭示函数的类型表明 Type[UserList[UserType]]
被简化为 Type[UserList]
.
使用 Callable
代替允许表达复杂类型实例化。可以定义精确的签名,包括 Sequence
而不是 UserList
:
def TypeSequence(usertype: Type[UserType]) -> Callable[[Iterable[UserType]], Sequence[UserType]]:
...