Теоретически можно выполнить sh часть его, сделав first
универсальный c протокол, который позволяет вам "захватить" возвращаемый тип __add__
. Например:
# If you are using Python 3.7 or earlier, you'll need to pip-install
# the typing_extensions module and import Protocol from there.
from typing import TypeVar, Protocol, Generic
TOther = TypeVar('TOther', contravariant=True)
TSum = TypeVar('TSum', covariant=True)
class SupportsAdd(Protocol, Generic[TOther, TSum]):
def __add__(self, other: TOther) -> TSum: ...
Затем вы можете сделать следующее:
S = TypeVar('S')
R = TypeVar('R')
# Due to how we defined the protocol, R will correspond to the
# return type of `__add__`.
def sum_two(first: SupportsAdd[S, R], second: S) -> R:
return first + second
# Type checks
reveal_type(sum_two("foo", "bar")) # Revealed type is str
reveal_type(sum_two(1, 2)) # Revealed type is int
reveal_type(sum_two(1.0, 2)) # Revealed type is float
# Does not type check, since float's __radd__ is ignored
sum_two(1, 2.0)
class Custom:
def __add__(self, x: int) -> int:
return x
# Type checks
reveal_type(sum_two(Custom(), 3)) # Revealed type is int
# Does not type check
reveal_type(sum_two(Custom(), "bad"))
Однако этот подход имеет несколько ограничений:
- не обрабатывать случаи, когда нет совпадения
__add__
в 'first', но есть совпадение __radd__
во 'second'. - Вы можете получить некоторые странные результаты, если вы измените Custom, так что
__add__
- перегрузка. Я думаю, что по крайней мере mypy в настоящее время имеет ошибку, из-за которой она не знает, как правильно обрабатывать сложные случаи, включающие подтипы и перегрузки.