5

为什么这样可以

class Ship:

    def __init__(self, parent):
        self.parent = parent

class Fleet:

    def __init__(self):
        self.ships = []

    def add_ship(self, ship: Ship):
        self.ships.append(ship)

但这不是吗?

class Fleet:

    def __init__(self):
        self.ships = []

    def add_ship(self, ship: Ship):
        self.ships.append(ship)

class Ship:

    def __init__(self, parent):
        self.parent = parent

我知道您在导入时不能有循环引用。但是,这不是导入的东西:它们都在同一个文件中。在这两种情况下,都定义了 Ship ,但似乎如果首先定义了 Fleet ,它就找不到 Ship 的定义。如果我曾经检查过类型,这不是真的。isinstance

def add_ship(self, ship):
    if isinstance(ship, Ship): # works fine
        self.ships.append(ship)

但是,这不允许我的 IDE (PyCharm) 查看定义和自动完成语法。

事实上,以下设计模式似乎工作正常

class Fleet:

    def __init__(self):
        self.ships = []

    def add_ship(self, ship):
        if isinstance(ship, Ship):
            self.ships.append(ship)

class Ship:

    def __init__(self, parent):
        if isinstance(parent, Fleet):
            self.parent = parent

但是,同样,不允许我的 IDE 找出类型。这是 Python 3.6.5/Anaconda/Windows 10。

4

1 回答 1

12

def add_ship(self, ship: Ship):定义时进行评估。那个时候Ship还没有定义。

if isinstance(ship, Ship):仅在被调用时才被评估add_ship。这将(希望)仅在Ship定义之后。

PEP 563(在 Python 3.7 及更高版本中实现)通过使类型注释评估变得惰性来解决此问题。

如果您升级,您可以添加from __future__ import annotations 到文件的顶部,该示例将起作用。

这将在 Python 4.0 中完全实现,这意味着from __future__ import annotations不需要。

Pre Python 3.7 解决方案

如果您不能或不想升级到 Python >= 3.7,则可以使用字符串文字注释(在我链接到的 PEP 中也提到过):

def add_ship(self, ship: 'Ship'):
于 2019-01-09T16:18:08.817 回答