Ссылаясь на атрибуты класса универсального типа - PullRequest
0 голосов
/ 12 июня 2019

У меня есть абстрактный базовый класс, который определяет несколько атрибутов класса, которые сами являются типами (т. Е. Вложенными типами);атрибуты переопределяются в конкретных производных классах, наследуемых от абстрактного класса.Конкретные производные классы используются с несколькими другими классами, которые аннотируются типом как обобщенные, где параметр типа имеет ограничение типа, которое он должен быть получен из абстрактного класса.Я хочу, чтобы эти другие классы (обобщения) ссылались на атрибуты класса (вложенные типы) конкретных классов.Следующий пример должен продемонстрировать идею:

import typing

class Base:
    A: typing.Type[Base]

class One(Base):
    class A(Base):  # overrides Base.A
        pass

class Two(Base):
    class A(One):  # overrides Base.A
        pass


T = typing.TypeVar('T', bound=Base)

class Foo(typing.Generic[T]):                 # the generic
    def foo(self, a: typing.Type[T.A]) -> T:  # <-- here, see T.A
        ...

f: Foo[Two] = Foo()
f.foo(Two.A)        # line 22 is here

MyPy v0.701 сообщает об ошибке в строке 22:

Аргумент 1 для "foo" из "Foo" имеет несовместимый тип"Наберите "А]";ожидаемый "Type [Two]"

MyPy, похоже, игнорирует ссылку на атрибут в T.A.Как мне понять, что я пытаюсь сослаться на тип, доступный через атрибут .A?Атрибут гарантированно будет доступен, потому что переменная типа T ограничена Base, которая имеет A.Обратите внимание, что расширение набора универсальных типов не вариант;Я мог бы уточнить это, но объяснение было бы слишком специфичным для моего приложения.

ОБНОВЛЕНИЕ: MyPy v0.711 с --new-semantic-analyzer дает более понятное сообщение об ошибке:

Имя 'TA' не определено

1 Ответ

0 голосов
/ 12 июня 2019

Я не уверен, помогает ли это или нет, но если вы параметризируете аргумент, привязанный к Base, он работает:

class Base:
    A: typing.Type['Base']


class One(Base):
    class A(Base):  # overrides Base.A
        pass


class Two(Base):
    class A(One):  # overrides Base.A
        pass


T = typing.TypeVar('T', bound='Base')
A = typing.TypeVar('A', bound='Base')


class Foo(typing.Generic[T, A]):    # the generic
    def foo(self, a: typing.Type[A]) -> T:  # <-- here, see T.A
        pass


f: Foo[Two, Two.A] = Foo()
f.foo(Two.A)        # line 22 is here

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...