Могу ли я использовать информацию о типе из другой функции в качестве типа возврата в Python? - PullRequest
1 голос
/ 30 января 2020

В следующем примере, как правильно аннотировать возвращаемый тип функции sum_two?

from typing import Any, TypeVar

T = TypeVar('T')
S = TypeVar('S')

def sum_two(first: T, second: S):
    return first + second

При условии, что оператор __add__ правильно аннотирован для всех возможных аргументов, которые будут переданы эта функция, есть ли способ express возвращаемый тип в качестве возвращаемого типа вызова __add__ для объектов типа T и S?

Я хотел бы избежать использования ввода overload Декоратор, чтобы определить все возможные случаи, так как могут быть десятки случаев.

1 Ответ

1 голос
/ 01 февраля 2020

Теоретически можно выполнить 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"))

Однако этот подход имеет несколько ограничений:

  1. не обрабатывать случаи, когда нет совпадения __add__ в 'first', но есть совпадение __radd__ во 'second'.
  2. Вы можете получить некоторые странные результаты, если вы измените Custom, так что __add__ - перегрузка. Я думаю, что по крайней мере mypy в настоящее время имеет ошибку, из-за которой она не знает, как правильно обрабатывать сложные случаи, включающие подтипы и перегрузки.
...