在具有泛型类型的类中定义的数据类的类型提示

Leo*_*ruz 6 python python-dataclasses python-typing

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

使用普通的类定义

# 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
Run Code Online (Sandbox Code Playgroud)

上面的代码通过了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'
Run Code Online (Sandbox Code Playgroud)

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)
Run Code Online (Sandbox Code Playgroud)

查明问题

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)
Run Code Online (Sandbox Code Playgroud)

上面的代码再次通过了测试,所以我认为问题出T在数据类定义中的引用。有谁知道未来如何解决这个问题以实现我最初的目标?

ale*_*ame 5

让我们从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
Run Code Online (Sandbox Code Playgroud)

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

__init__现在让我们回答为什么该示例适用于带有变量的函数的问题TypeVar

__init__这是因为mypy 将该方法视为具有自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)'. ieT不受限于int此处。