Тип подсказки для атрибута класса - PullRequest
0 голосов
/ 15 сентября 2018

У меня есть веб-приложение со многими моделями и множеством представлений на основе классов.Большая часть кода выглядит следующим образом:

from typing import TypeVar, Type

M = TypeVar('M', bound='Model')
TypeModel = Type[M]


# ----------  models
class Model:
    @classmethod
    def factory(cls: TypeModel) -> M:
        return cls()


class ModelOne(Model):
    def one(self):
        return


class ModelTwo(Model):
    def two(self):
        return


# ----------  views
class BaseView:
    model: TypeModel

    @property
    def obj(self) -> M:
        return self.model.factory()

    def logic(self):
        raise NotImplementedError


class One(BaseView):
    model = ModelOne

    def logic(self):
        self.obj.  # how can i get suggest of methods of ModelOne here?
        ...


class Two(BaseView):
    model = ModelTwo

    def logic(self):
        self.obj.  # how can i get suggest of methods of ModelTwo here?
        ...

Я хочу иметь свойство obj, которое является экземпляром указанной модели в представлении.Как мне этого добиться?Спасибо

1 Ответ

0 голосов
/ 17 сентября 2018

Вам необходимо сделать ваш класс BaseView родовым по отношению к M. Итак, вы должны сделать что-то вроде этого:

from typing import TypeVar, Type, Generic

M = TypeVar('M', bound='Model')

# Models

class Model:
    @classmethod
    def factory(cls: Type[M]) -> M:
        return cls()

class ModelOne(Model):
    def one(self):
        return

class ModelTwo(Model):
    def two(self):
        return

# Views

# A BaseView is now a generic type and will use M as a placeholder.
class BaseView(Generic[M]):
    model: Type[M]

    @property
    def obj(self) -> M:
        return self.model.factory()

    def logic(self):
        raise NotImplementedError

# The subclasses now specify what kind of model the BaseView should be
# working against when they subclass it.
class One(BaseView[ModelOne]):
    model = ModelOne

    def logic(self):
        self.obj.one()

class Two(BaseView[ModelTwo]):
    model = ModelTwo

    def logic(self):
        self.obj.two()

Одно примечание: я избавился от вашего псевдонима типа TypeModel. Это отчасти стилистическое и отчасти прагматичное.

Стилистически, когда я смотрю на сигнатуру типа, я хочу иметь возможность сразу определить, использует ли он generics / typevars или нет. Использование псевдонимов типов скрывает, что / я действительно не люблю использовать контекстно-зависимые типы.

Прагматично, и средство проверки типов PyCharm, и mypy, как правило, испытывают небольшие трудности, когда вы чрезмерно используете псевдонимы типов, содержащие typevars.

...