type(self) 的方法签名参数

Method signature arguments of type(self)

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

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()

这会导致以下错误:

NameError: name 'Dummy' is not defined

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

class Dummy:
    def __init__(self, value: int, previous=None):
        assert type(previous) is Dummy or previous is None
        ...

虽然我同意,但这是一个相当丑陋 hack,你也可以使用字符串作为类型提示:

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

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

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

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

When a type hint contains names that have not been defined yet, that definition may be expressed as a string literal, to be resolved later.

A situation where this occurs commonly is the definition of a container class, where the class being defined occurs in the signature of some of the methods. For example, the following code (the start of a simple binary tree implementation) does not work:

class Tree:
    def __init__(self, left: Tree, right: Tree):
        self.left = left
        self.right = right

To address this, we write:

class Tree:
    def __init__(self, left: 'Tree', right: 'Tree'):
        self.left = left
        self.right = right

The string literal should contain a valid Python expression (i.e., compile(lit, '', 'eval') should be a valid code object) and it should evaluate without errors once the module has been fully loaded. The local and global namespace in which it is evaluated should be the same namespaces in which default arguments to the same function would be evaluated.

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