Так мне кажется, что вы хотите использовать переменные типа / обобщения? То есть, когда вызывается функция, эта переменная типа затем привязывается к этому конкретному вызову.
Например, у нас может быть функция head()
, которая необязательно возвращает элемент заголовка однородного списка (Python не имеет этого ограничения для списков, но пока представьте, что мы хотим иметь):
from typing import TypeVar, Optional, List
T = TypeVar("T", int, float, str)
def head(lst: List[T]) -> Optional[T]:
if lst:
return lst[0]
return None
print(head([1, 2]))
print(head(["koi"]))
print(head([]))
Теперь для этих списков разрешены любые типы str, float или int, но они должны быть однородными . Таким образом, сигнатура типа в основном гласит, что «head принимает список строк, целых чисел или чисел с плавающей запятой, и какой бы тип элементов ни был в списке, возвращаемое значение (если оно есть) тоже будет того же типа»
Обратите внимание, что это сильно отличается от типов объединения, например. у вас может быть
T = Union[str, float, int]
def head(lst: List[T]) -> Optional[T]:
...
, но тогда он не будет работать так, как вы хотите; в соответствии с типами, возврат int все равно будет в порядке, даже если список содержит только строки.
Обновление : как любезно упомянуто @MisterMiyagi в комментарии ниже, это по-прежнему требует, чтобы пользователь знал допустимых типов.
Для вашего варианта использования (с классами) это должно быть нормально (пытаясь использовать минимальный пример):
from typing import TypeVar, Generic
T = TypeVar("T")
class A(Generic[T]):
def a(self, a: T, b: T) -> T:
return a
print(A[int]().a(1, 2))
print(A[float]().a(32.1, 2))
print(A[str]().a("koi", "bar"))
# print(A[int]().a(1, "bar")) -- does not pass type checker
Существенная разница в том, что вам все еще нужно для передачи типов при их фактическом вызове, но они не обязательно должны присутствовать при определении вашего класса generi c.
Проверьте https://mypy.readthedocs.io/en/stable/generics.html для получения дополнительной информации о них .