我正在尝试使用工厂函数生成一些类型注释 - 特别是对于tuple
类型。我有一个版本的工厂工作正常(如在,它编译,运行,并在MyPy中令人满意地检查):
import typing as tx
HomogenousTypeVar = tx.TypeVar('HomogenousTypeVar')
TupleTypeReturnType = tx.Type[tx.Tuple[HomogenousTypeVar, ...]]
def TupleType(length: int,
tuptyp: tx.Type[HomogenousTypeVar] = str) -> TupleTypeReturnType:
""" Create a type annotation for a tuple of a given type and length """
assert length > 0
return tx.Tuple[tuple(tuptyp for idx in range(length))]
...用法如:
class Thing(object):
__slots__: TupleType(2) = ('yo', 'dogg')
other_fields: TupleType(4) = ('i', 'heard',
'you', 'like')
# etc, or what have you
...但是,当我尝试添加对typing.ClassVar
注释的支持时,我没有成功,看起来像这样:
import typing as tx
HomogenousTypeVar = tx.TypeVar('HomogenousTypeVar')
TupleTypeReturnType = tx.Union[tx.Type[tx.Tuple[HomogenousTypeVar, ...]],
tx.Type[tx.ClassVar[tx.Tuple[HomogenousTypeVar, ...]]]]
def TupleType(length: int,
tuptyp: tx.Type[HomogenousTypeVar] = str,
clsvar: bool = False) -> TupleTypeReturnType:
""" Create a type annotation for a tuple of a given type and length,
specifying additionally whether or not it is a ClassVar """
assert length > 0
out = tx.Tuple[tuple(tuptyp for idx in range(length))]
return clsvar and tx.ClassVar[out] or out
...在此更改之后,代码甚至不会在最初编译 - 它无法使用TypeError
模块内部的typing
执行此操作:
TypeError:typing.ClassVar [typing.Tuple [~HomogenousTypeVar,...]]作为类型参数无效
......随着错误的发生,让我感到有点打电话;我的意思是,并不是typing
中的所有内容都应该是某种形式的有效类型论证,是否采取?
在the typing
source code related to ClassVar
中,文档字符串中提到的使用有一些限制 - 但这不是其中之一。有什么明显的东西我不见了吗?我试图以这种方式使用这种注释是一种不切实际的注释吗?我还能尝试什么?
您确定原始代码段实际上是使用mypy进行类型检查吗?当我尝试使用Mypy 0.620或github的最新版本运行它时,我收到以下错误:
test.py:13: error: invalid type comment or annotation
test.py:13: note: Suggestion: use TupleType[...] instead of TupleType(...)
test.py:14: error: invalid type comment or annotation
test.py:14: note: Suggestion: use TupleType[...] instead of TupleType(...)
我也无法重现您使用ClassVar代码时出现的错误 - 当我尝试运行它时,我收到以下错误:
test.py:4: error: Invalid type: ClassVar nested inside other type
test.py:6: error: Incompatible default for argument "tuptyp" (default has type "Type[str]", argument has type "Type[HomogenousTypeVar]")
test.py:12: error: Invalid type alias
test.py:13: warning: Returning Any from function declared to return "Union[Type[Tuple[HomogenousTypeVar?, ...]], Type[Tuple[HomogenousTypeVar?, ...]]]"
test.py:15: error: Name 'Thing' is not defined
test.py:16: error: Revealed type is 'Any'
你确定你实际上在运行mypy,而不是只运行代码吗?例如。如果你只运行python3 test.py
,你基本上就是跳过所有的类型检查(除了在打字模块中内置的一些最小的健全性检查)。
如果要对代码进行类型检查,则需要pip-install mypy并运行python3 -m mypy test.py
。
在任何情况下,所有这些错误消息都是预期的行为 - mypy(以及任何其他符合PEP 484的类型检查程序)只能静态分析您的代码,并且不会尝试运行或分析任何工厂函数/任何类型提示生成函数可以试着写。
所以,这意味着,如果您希望PEP 484兼容工具能够分析您的代码,那么您将无法使用生成的类型提示与ClassVars - 他们无法理解/解释您的原始类型提示集,并且添加ClassVars肯定无济于事。
如果你想生成类型提示,我能想到的唯一真正的选择是在Python之上发明某种迷你语言或宏系统,在运行时会产生Python代码。然后,您将运行并检查生成的代码而不是宏的Python语言。
但我真的不建议这样做 - 这是一个非常脆弱的黑客。
更广泛地说,每当您开始遇到这些与类型相关的限制时,我认为这表明您的代码太复杂了。我要么考虑简化代码,要么(如果不可能)切换到像Haskell或Idris这样的语言,这样可以让你使用更具表现力(虽然更复杂)的类型系统。
例如,在这种情况下,您试图推广Tuple类型 - 这使我推断您的代码库包含许多不同类型的不同元素和元组的元组。
这让我感到有点怀疑 - 我会考虑将这些元组中的一些转换为常规类或(如果你仍然需要类似元组的功能)namedtuple。 Dataclasses(这是新的as of Python 3.7)在这里也很方便。
这些解决方案还有助于使您的代码更具可读性 - 您现在可以为每种不同类型的元组提供具体的名称和含义。
或者,如果您只有几个不同类型的元组,但在整个地方使用这些元组,您可以尝试使用type aliases,这样您就不必反复重复键入相同(长)类型。例如。而不是做:
def foo(x: Tuple[int, int, int, int]) -> None: ...
......你可以这样做:
IpAddress = Tuple[int, int, int, int]
def foo(x: IpAddress) -> None: ...