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

标签 python python-typing python-dataclasses

我知道标题很困惑,所以我以二叉搜索树为例:
使用普通的类定义

# 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的引用在数据类定义中。有谁知道 future 如何解决这个问题以满足我最初的目标?

最佳答案

让我们从 PEP 484 中写的内容开始关于类型变量的范围规则:

A generic class nested in another generic class cannot use same type variables. The scope of the type variables of the outer class doesn't cover the inner one:

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 的函数多变的。
这是因为方法__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)' .即 T不绑定(bind)到 int这里。

关于python - 在具有泛型类型的类中定义的数据类的类型提示,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63978820/

相关文章:

python - 使用哨兵值作为默认值的类型提示参数

python - 数据类中的类属性和元类

python - 如何使用 pandas 数据框中该行中的字段查找和修改特定行?

python - 替代 sklearn.model_selection import GridSearchCV

Python csv.reader vs csv.dictreader 区别?

python - 我怎样才能告诉 PyCharm 参数应该是什么类型?

python - Pylance 要求在一致的列表变量上显式类型

python - For 循环和系列的真值不明确

python-3.x - 使用 @dataclass 获取没有变量 fild 的类变量的字典(repr=False)

python - 如何在 Python 中将对象 A 中的数据合并到对象 B 中?