В дополнение к хорошим ответам, упомянутым выше. Мой вариант использования - миксин для использования в тестах.
По предложению самого Гвидо ван Россума здесь:
from typing import *
T = TypeVar('T')
class Base:
fit: Callable
class Foo(Base):
def fit(self, arg1: int) -> Optional[str]:
pass
class Bar(Foo):
def fit(self, arg1: float) -> str:
pass
Таким образом, когда дело доходит до миксина, это может выглядеть следующим образом:
class UsefulMixin:
assertLess: Callable
assertIn: Callable
assertIsNotNone: Callable
def something_useful(self, key, value):
self.assertIsNotNone(key)
self.assertLess(key, 10)
self.assertIn(value, ['Alice', 'in', 'Wonderland']
class AnotherUsefulMixin:
assertTrue: Callable
assertFalse: Callable
assertIsNone: Callable
def something_else_useful(self, val, foo, bar):
self.assertTrue(val)
self.assertFalse(foo)
self.assertIsNone(bar)
И наш последний класс будет выглядеть следующим образом:
class TestSomething(unittest.TestCase, UsefulMixin, AnotherUsefulMixin):
def test_something(self):
self.something_useful(10, 'Alice')
self.something_else_useful(True, False, None)
Один из подходов, которые я видел в этом вопросе, - это подсказка типа для атрибута self
. Вместе с Union
из пакета для ввода вы можете использовать атрибуты из класса, который используется вместе с вашим миксином, при этом сохраняя правильную подсказку типа для собственных атрибутов:
from typing import Union
class AdditionMixin:
def add(self: Union[MyBaseClass, 'AdditionMixin'], b: int) -> int:
return self.value + b
class MyBaseClass:
def __init__(self, value: int):
self.value = value
Недостатком является то, что вы должны добавить подсказку к каждому методу, что довольно громоздко.