可选或与Python类中的前向引用联合,由mypy错误标记

时间:2019-11-05 23:17:38

标签: python-3.x mypy

我定义了一个带有类型注释的TreeNode类。它接受__init__和某些类方法中的参数的TreeNode或None。完整的代码在测试过程中运行良好,但是当我用mypy检查时,它会列出4条警告。我正在使用Python 3.7.4和mypy版本0.74。

我使用Optional [“ TreeNode”]和Union [“ TreeNode”,None]关键字尝试了此操作,但是错误仍然存​​在。请注意,TreeNode周围的引号是必需的,因为它是在完全定义类型之前对类型的前向引用。

from typing import *

class TreeNode():
    def __init__(self, value,
                 parent : Optional["TreeNode"]=None,
                 left_child : Optional["TreeNode"]=None,
                 right_child : Optional["TreeNode"]=None):
        self.value = value
        self.parent = parent
        self.left_child = None
        self.right_child = None
        self.update_children(left_child, right_child)

    def get_parent(self):
        return self.parent

    def set_parent(self, other):
        self.parent = other

    def update_children(self,
                        left_child : Optional["TreeNode"] = None,
                        right_child : Optional["TreeNode"] = None):
        # update parents in children, if left or right not None.
        if left_child:
            self.left_child = left_child
            self.left_child.set_parent(self)
        if right_child:
            self.right_child = right_child
            self.right_child.set_parent(self)

    def depth(self):
        pass # full code omitted for brevity

这是mypy的输出:

tree_node.py:25: error: Incompatible types in assignment (expression has type "TreeNode", variable has type "None")
tree_node.py:26: error: "None" has no attribute "set_parent"
tree_node.py:28: error: Incompatible types in assignment (expression has type "TreeNode", variable has type "None")
tree_node.py:29: error: "None" has no attribute "set_parent"

我还尝试了对mypy抱怨的代码进行以下修改,但无济于事:

        if left_child is not None:
            self.left_child = left_child
            self.left_child.set_parent(self)
        if right_child is not None:
            self.right_child = right_child
            self.right_child.set_parent(self)

问题是当我明确指出TreeNode或None都可以,并且仅在不为None的情况下执行有问题的代码时,为什么会出现这些错误。

1 个答案:

答案 0 :(得分:0)

问题与您在构造函数中设置左右孩子的方式有关-具体来说,这两行:

self.left_child = None
self.right_child = None

由于这些字段被分配了None值,因此mypy最终只能保守地推断出这些字段的类型恰好是None。并且Optional[TreeNode]不是None的子类型,因此update_children中的赋值最终失败。

(Mypy从理论上可以观察到update_children在构造函数内部被调用,并使用那里的赋值来为您的字段推断出更准确的类型,但是这种逻辑实施起来非常棘手。)

在这种情况下,解决方法是仅显式地为这两个字段提供类型提示。例如,如果您使用的是Python 3.6+,则可以使用变量注释:

self.left_child: Optional[TreeNode] = None
self.right_child: Optional[TreeNode] = None

或者,如果您想支持较旧的Python版本,则可以使用基于注释的语法:

self.left_child = None   # type: Optional[TreeNode]
self.right_child = None  # type: Optional[TreeNode]