Тип подсказывает список со связанным наследованием - PullRequest
1 голос
/ 02 марта 2020

Я использую Python 3.7.6 с PyCharm. Я хочу, чтобы мой код работал как хороший внутренний API, а для объектов появлялось завершение кода, поэтому я хочу использовать типизацию.

Я пытаюсь найти хороший шаблон для случаев, когда:

  • Есть две группы классов, каждая из которых имеет свое собственное дерево наследования
  • и объекты из одна группа состоит из списков объектов из другой группы

(пример ниже)

Я нашел способ ниже, но это похоже на хак. Какой правильный (или лучший) способ сделать это?

from typing import List, Type

class Leg:
    def step(self):
        print("step")

class DuckLeg(Leg):
    def paddle(self):
        print("splosh")

class Biped:
    def __init__(self, leg_type: Type[Leg]):
        self.legs: List[leg_type] = [leg_type(), leg_type()]

    def walk(self):
        for leg in self.legs:
            leg.step()

class Duck(Biped):
    def __init__(self):
        super().__init__(leg_type=DuckLeg)
        self.legs: List[DuckLeg] = self.legs  # A hack?

my_duck = Duck()
my_duck.walk()              # code-completion appears for .walk()
my_duck.legs[0].paddle()    # code-completion appears for .paddle()

Редактировать 1: Этот вопрос не о том, где разместить аннотации типов, а о том, как обеспечить завершение кода в этом контексте. Если следующая строка закомментирована ...

self.legs: List[DuckLeg] = self.legs

... код все равно будет выполняться из-за утки, но завершение кода не будет отображаться для .paddle () и при ручном вводе PyCharm Инспекция кода сообщит: Неразрешенная ссылка на атрибут 'paddle' для класса 'Leg'.

1 Ответ

0 голосов
/ 02 марта 2020

Не уверен, решит ли это на самом деле вашу проблему, но я думаю, что она чище, чем вы предлагаете:

from typing import List, Type

class Leg:
    def step(self):
        print("step")

class DuckLeg(Leg):
    def paddle(self):
        print("splosh")

class Biped:
    LegType = Leg
    def __init__(self):
        # self.LegType always gives the correct leg type for the instance
        self.legs: List[self.LegType] = [self.LegType(), self.LegType()]

    def walk(self):
        for leg in self.legs:
            leg.step()

class Duck(Biped):
    LegType = DuckLeg
    def __init__(self):
        super().__init__()
...