在具有泛型类型的类中定义的数据类的类型提示 使用普通的类定义使用dataclass 指出问题所在

问题描述

我知道标题很混乱,所以让我以二进制搜索树为例:

使用普通的类定义

# This code passed mypy test
from typing import Generic,TypeVar

T = TypeVar('T')
class BST(Generic[T]):
    class Node:        
        def __init__(
            self,val: T,left: 'BST.Node',right: 'BST.Node'
        ) -> None:
            self.val = val
            self.left = left
            self.right = right

以上代码通过了mypy测试。

使用dataclass

但是,当我尝试使用dataclass简化Node的定义时,代码在mypy测试中失败了。

# This code failed to pass mypy test
from dataclasses import dataclass
from typing import Generic,TypeVar

T = TypeVar('T')
class BST(Generic[T]):
    @dataclass
    class Node:
        val: T
        left: 'BST.Node'
        right: 'BST.Node'

mypy给了我这个错误消息:(test_typing.py:8是第val: T行)

test_typing.py:8: error: Type variable "test_typing.T" is unbound
test_typing.py:8: note: (Hint: Use "Generic[T]" or "Protocol[T]" base class to bind "T" inside a class)
test_typing.py:8: note: (Hint: Use "T" in function signature to bind "T" inside a function)

指出问题所在

# This code passed mypy test,suggest the problem is the reference to `T` in the dataclass definition
from dataclasses import dataclass
from typing import Generic,TypeVar

T = TypeVar('T')
class BST(Generic[T]):
    @dataclass
    class Node:
        val: int # chose `int` just for testing
        left: 'BST.Node'
        right: 'BST.Node'

以上代码再次通过了测试,因此我认为问题在于数据类定义中对T的引用。有人知道将来如何解决此问题以实现我的最初目标吗?

解决方法

让我们从PEP 484中写的有关类型变量的作用域规则的内容开始:

嵌套在另一个通用类中的通用类不能使用相同类型的变量外部类的类型变量的范围不覆盖内部的

T = TypeVar('T')
S = TypeVar('S')

class Outer(Generic[T]):
   class Bad(Iterable[T]):       # Error
       ...
   class AlsoBad:
       x = None  # type: List[T] # Also an error

   class Inner(Iterable[S]):     # OK
       ...
   attr = None  # type: Inner[T] # Also OK

这就是为什么您的带有嵌套装饰类的示例不起作用的原因。

现在让我们回答一个问题,为什么该示例与带有__init__变量的TypeVar函数一起使用。

这是因为mypy将方法__init__视为具有独立TypeVar变量的通用方法。例如,reveal_type(BST[int].Node.__init__)显示Revealed type is 'def [T,T] (self: main.BST.Node,val: T'-1,left: main.BST.Node,right: main.BST.Node)'。即T在此处未绑定到int

,

嵌套类不能从其包含的类中隐式使用TypeVar:嵌套类必须是Generic,并且绑定的TypeVar

BT = TypeVar('BT')
NT = TypeVar('NT')

class BST(Generic[BT]):
    root: 'BST.Node[BT]'  # root note is of same type as search tree

    @dataclass
    class Node(Generic[NT]):  # generic node may be of any type
        val: NT
        left: 'BST.Node[NT]'
        right: 'BST.Node[NT]'

当嵌套类在其包含类之外进行引用时,这将使嵌套类具有良好的定义。潜在的问题是嵌套类与外部专家分开存在–推论仅知道BST.NodeBST.Node[T],而不知道BST[T].Node


由于嵌套没有提供任何功能优势,因此使用相同的TypeVar

定义单独的类通常更简单
T = TypeVar('T')

class BST(Generic[T]):
    root: 'Node[T]'

@dataclass
class Node(Generic[T]):
    val: T
    left: 'Node[T]'
    right: 'Node[T]'

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...