类型为(self)的方法签名参数

Eli*_* Mi 5 python oop methods method-signature python-3.x

当我定义一个类时,如何在其方法的签名中包含必须属于同一类的参数?我正在构建一个应该像这样工作的图形结构,但这里是一个简化的示例:

class Dummy:
    def __init__(self, value: int, previous: Dummy=None):
        self._value = value
        self._previous = previous

    @property
    def value(self):
        return self._value

    def plus_previous(self):
        return self.value + self._previous.value

d1 = Dummy(7)
d2 = Dummy(3, d1)
d2.plus_previous()
Run Code Online (Sandbox Code Playgroud)

这会导致以下错误:

NameError: name 'Dummy' is not defined
Run Code Online (Sandbox Code Playgroud)

我的意思是,我可以用 Python 2 的方式来做,但我希望有一个比这更多的 python-3-ic 解决方案:

class Dummy:
    def __init__(self, value: int, previous=None):
        assert type(previous) is Dummy or previous is None
        ...
Run Code Online (Sandbox Code Playgroud)

Wil*_*sem 4

尽管我同意,但这是一个相当丑陋的黑客,您也可以使用字符串作为类型提示:

class Dummy:
    def __init__(self, value: int, previous: 'Dummy'=None):
        self._value = value
        self._previous = previous

    @property
    def value(self):
        return self._value

    def plus_previous(self):
        return self.value + self._previous.value
Run Code Online (Sandbox Code Playgroud)

正如PEP-484中关于类型提示的描述:

当类型提示包含尚未定义的名称时,该定义可以表示为字符串文字,稍后解析

这种情况常见的情况是容器类的定义,其中所定义的类出现在某些方法的签名中。例如,以下代码(简单二叉树实现的开始)不起作用:

class Tree:
    def __init__(self, left: Tree, right: Tree):
        self.left = left
        self.right = right
Run Code Online (Sandbox Code Playgroud)

为了解决这个问题,我们写道:

class Tree:
    def __init__(self, left: 'Tree', right: 'Tree'):
        self.left = left
        self.right = right
Run Code Online (Sandbox Code Playgroud)

字符串文字应该包含一个有效的Python表达式(即 compile(lit, '', 'eval')应该是一个有效的代码对象),并且一旦模块完全加载,它的计算应该没有错误。计算它的本地和全局命名空间应该与计算同一函数的默认参数的命名空间相同。

然而,此 hack 的一个问题是,如果您在 IDE 中进行重命名,IDE 绝对有可能不会考虑这些字符串文字,因此无法重命名它们。