Общие типы и наследование Python: трудности с классами аннотирования, возвращающими взаимные экземпляры друг другаPython

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

Сообщение 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

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 должен работать с как конкретный тип ( на самом деле все еще общий класс):

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

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, который помечен буквой A.

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

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 , надеясь получить правильное разрешение GetTher , разрешение 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
3. Отдельные базовые классы
Третья попытка, которую я предпринял, заключалась в том, чтобы разделить универсальную и неуниверсальную часть класса 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»