Почему упорядочение имеет значение в подсказках типа Python? - PullRequest
0 голосов
/ 09 января 2019

Почему это нормально

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

Я знаю, что при импорте нельзя использовать циклические ссылки. Однако это не импортная вещь: оба они находятся в одном файле. В обоих случаях определение «Корабль» сделано, но кажется, что если «Флот» определен первым, он не может найти определение «Корабль». Это не true, если я использовал 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.

1 Ответ

0 голосов
/ 09 января 2019

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'):
...