使用工厂函数在Python 3.7中生成注释类型时出现“typing.ClassVar”的问题

问题描述 投票:1回答:1

我正在尝试使用工厂函数生成一些类型注释 - 特别是对于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中,文档字符串中提到的使用有一些限制 - 但这不是其中之一。有什么明显的东西我不见了吗?我试图以这种方式使用这种注释是一种不切实际的注释吗?我还能尝试什么?

python python-3.x tuples mypy python-typing
1个回答
1
投票

您确定原始代码段实际上是使用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类型 - 这使我推断您的代码库包含许多不同类型的不同元素和元组的元组。

这让我感到有点怀疑 - 我会考虑将这些元组中的一些转换为常规类或(如果你仍然需要类似元组的功能)namedtupleDataclasses(这是新的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: ...
© www.soinside.com 2019 - 2024. All rights reserved.