Связанные ссылки в аннотациях типа Python - PullRequest
0 голосов
/ 28 мая 2018

Скажем, у меня есть функция, которая принимает значение и произвольное количество функций, давайте вызовем функцию для chain_call.

Без типов простая наивная реализация была бы:

def chain_call(input_value, *args):
    for function in args:
        input_value = function(input_value)
    return input_value

Как вы понимаете, input_value может быть чем угодно, но оно всегда совпадает с первым и единственным обязательным аргументом первого Callable в *args: List[Callable].

Отсюда и далее первый и единственный обязательный аргумент Callable - это тот же тип, что и у возвращаемого типа предыдущих элементов.

До сих пор мне удалось определить довольно универсальныйтипа, но это слишком свободно

def chain_call(input_value: Any, *args: List[Callable[Any], Any]) -> Any: ...

Что мне действительно нравится, так это что-то вроде

T = TypeVar('T')

def chain_call(input_value: T, *args: List[Callable[T, ...], tr]) -> tr: ...

Где T для Callable n+1 равно tr из Callable n, а окончательный тип возвращаемого значения равенtr Callable n_maxЯ не уверен, как выразить это с помощью системы типов, и я хотел бы получить любое руководство.

1 Ответ

0 голосов
/ 01 июня 2018

К сожалению, в настоящее время это не то, что можно печатать, используя подсказки типа PEP 484.

Лучшее, что вы можете сделать, это использовать перегрузки для аппроксимации подписи: в основном, мы жестко кодируем, какой должна быть подпись до определенного числа, затем возвращаемся к выводу 'Any':

from typing import TypeVar, overload, Any, Callable

T1 = TypeVar('T1')
T2 = TypeVar('T2')
T3 = TypeVar('T3')
T4 = TypeVar('T4')

@overload
def chain_call(input_value: T1, 
               *f_rest: Callable[[T1], T1]) -> T1: ...
@overload
def chain_call(input_value: T1, 
               f1: Callable[[T1], T2],
               f2: Callable[[T2], T3],
               f3: Callable[[T3], T4],
               f4: Callable[[T4], Any],
               *f_rest: Callable[[Any], Any]) -> Any: ...
@overload
def chain_call(input_value: T1, 
               f1: Callable[[T1], T2],
               f2: Callable[[T2], T3],
               f3: Callable[[T3], T4]) -> T4: ...
@overload
def chain_call(input_value: T1, 
               f1: Callable[[T1], T2],
               f2: Callable[[T2], T3]) -> T3: ...
@overload
def chain_call(input_value: T1, 
               f1: Callable[[T1], T2]) -> T2: ...
def chain_call(input_value, *f_rest):
    for function in f_rest:
        input_value = function(input_value)
    return input_value

Здесь я жестко запрограммировал, что должно происходить с 3 входными функциями (и начал с перегрузки для особого случая, когда все вызываемые объекты имеют одинаковый тип входа и выхода).

Этот метод заключается в том, как в настоящее время typhed печатает такие вещи, как функция zip, которая может принимать произвольное число итераций.

Примечание: вам может понадобиться использовать последнюю версию mypy from master для этого кода для дословной работы,

...