Python два параметра универсального c метода для одного и того же конкретного типа - PullRequest
0 голосов
/ 06 августа 2020

Как я могу проверить, что параметры функции имеют один и тот же конкретный тип?

Пример:

class A(Generic[T]):
   def __init__(p: T):
       self._p = p

   def get_data(self) -> T:
       return self._p

class B(Generic[T]):
   def __init__(p: T):
       self._p = p
   
   def inc(v: A[T]):
       self._p = self._p + v.get_data()

class I(Generic[T]):
   def __init__(a: A[T], b: B[T]):
       self._a = a
       self._b = b

   def execute():
       self._b.inc(a)

Хорошо:

I(A(1), B(2)).execute()

Ошибка:

I(A(1), B("2")).execute()

1 Ответ

1 голос
/ 06 августа 2020

Так мне кажется, что вы хотите использовать переменные типа / обобщения? То есть, когда вызывается функция, эта переменная типа затем привязывается к этому конкретному вызову.

Например, у нас может быть функция 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 для получения дополнительной информации о них .

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