Python Generic Types & Wondatence: борьба с аннотированием классов, возвращающих взаимные экземпляры друг другаPython

Программы на Python
Ответить Пред. темаСлед. тема
Anonymous
 Python Generic Types & Wondatence: борьба с аннотированием классов, возвращающих взаимные экземпляры друг друга

Сообщение Anonymous »

Я пытаюсь аннотировать типы для некоторых классов и подклассов.
Вот ситуация до аннотаций. Проблема заключается в том, как правильно аннотировать getOther(), чтобы средства проверки статического типа правильно определяли тип возвращаемого значения для всех подклассов, без необходимости переопределять его для подклассов SubB1 и SubB2.
Кроме того, SubB1 и SubB2 должны оставаться подклассами из Б.

Код: Выделить всё

class A:
def __init__(self, a:int) -> None:
self.a:int = a

class SubA1(A): ...
class SubA2(A): ...

class B:
_otherClass = A

def __init__(self, b:int) -> None:
self.b:int = b

def getOther(self): #  type checker: SubA1
b2.getOther() # Returns SubA2(2) => type checker: SubA2
Я пробовал несколько подходов, но каждый по той или иной причине не удался:
1. Сделать B универсальным классом:

Код: Выделить всё

from typing import TypeVar, Generic

class A:
def __init__(self, a:int) -> None:
self.a:int = a

class SubA1(A): ...
class SubA2(A): ...

Aclass = TypeVar('Aclass')

class B(Generic[Aclass]):
_otherClass = A

def __init__(self, b:int) -> None:
self.b:int = b

def getOther(self) -> Aclass:
return self._otherClass(a = self.b)

class SubB1(B[SubA1]):
_otherClass = SubA1
class SubB2(B[SubA2]):
_otherClass = SubA2
Это работает для SubB1 и SubB2, но не для самого B, поскольку нигде не указано, что B должен работать с A как конкретный тип ( на самом деле все еще общий класс):

Код: Выделить всё

b0 = B(0)
b1 = SubB1(1)
b2 = SubB2(2)

_ = b0.getOther() # Type checker => Any, Not OK
_ = b1.getOther() # Type checker => SubA1, OK
_ = b2.getOther() # Type checker => SubA2, OK
< /code>
[b] 2. Отдельный общий класс для getother 
[/b]
Вторая попытка состояла от него с использованием множественного наследования: < /p>

Код: Выделить всё

...

class _GenericB(Generic[Aclass]):
def getOther(self) -> Aclass:
return self._otherClass(a = self.b)

class B(_GenericB[A]):
_otherClass = A

def __init__(self, b:int) -> None:
self.b:int = b

class SubB1(B, _GenericB[SubA1])
class SubB1(B, _GenericB[SubA2])
Теперь это работает для b , но не для subb1 и subb2 , поскольку множественное наследство такое, что getother вызвано Subb1 и subb2 решается к методу, определенному в b , который аннотируется .

Код: Выделить всё

b0 = B(0)
b1 = SubB1(1)
b2 = SubB2(2)

_ = b0.getOther() # Type checker => A, OK
_ = b1.getOther() # Type checker => A, Not OK
_ = b2.getOther() # Type checker => A, Not OK
Я также попробовал изменить порядок B и _GenericB в SubB1 и SubB2, надеясь получить правильное разрешение getOther , разрешение MRO не выполнено: (

Код: Выделить всё

TypeError: Cannot create a consistent method resolution order (MRO) for bases _GenericB, B'
):

Код: Выделить всё

...
class SubB1(_GenericB[SubA1], B) # B after _GenericB raises MRO resolution TypeError
class SubB1(_GenericB[SubA2], B) # B after _GenericB raises MRO resolution TypeError
< /code>
[b] 3. Отдельные базовые классы [/b] 
Третья попытка, которую я предпринял, - это разделить общую и не общая часть класса B 
на отдельные базовые классы, имея b , Subb1 и subb2 наследуют от них.
Это, однако, нарушает отношения наследования:

Код: Выделить всё

...

class _NongenericB:
def __init__(self, b:int) -> None:
self.b:int = b

class _GenericB(Generic[Aclass]):
def getOther(self) -> Aclass:
return self._otherClass(a = self.b)

class B(_NongenericB, _GenericB[A]):
_otherClass = A

class SubB1(_NongenericB, _GenericB[SubA1]):
_otherClass = SubA1

class SubB2(_NongenericB, _GenericB[SubA2]):
_otherClass = SubA2
< /code>
Однако: < /p>
_ = b0.getOther() # Type checker => A, OK
_ = b1.getOther() # Type checker => SubA1, OK
_ = b2.getOther() # Type checker => SubA2, OK

assert isinstance(b0, B) # OK
assert isinstance(b1, B) # Assertion error
assert isinstance(b2, B) # Assertion error
Кроме того, я не могу добавить b в базовые классы subb1 и subb2 , потому что я получаю в той же ситуации точки 2.

Я немного не в себе. Что мне делать? Возможно, так как может быть много методов, работающих с этим механизмом.
Использование метода, определяемого в базовом классе раз и навсегда, будет идеальным решением. < /p>
Есть идеи? < / p>
Спасибо! < /p>

Подробнее здесь: https://stackoverflow.com/questions/793 ... rning-reci
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «Python»