Тип аннотации для функции, возвращающей функцию, принимающую args и kwargs - PullRequest
0 голосов
/ 09 сентября 2018

Следующий пример кода работает во время выполнения, но не принимается mypy --strict:

from typing import Any, Callable, TypeVar

TypeT = TypeVar('TypeT')


def log_call(msg: str) -> Callable[..., TypeT]:
    def do_call(func: Callable[..., TypeT], *args: Any, **kwargs: Any) -> TypeT:
        print(msg)
        return func(*args, **kwargs)

    return do_call


def double(val: int) -> int:
    return 2 * val


def plus(a: int, b: int) -> int:
    return a + b


def plus_plus(a: int, b: int, c: int) -> int:
    return a + b + c


result_1 = log_call('hi')(double, 1)
result_2 = log_call('hi')(plus, 2, 3)
result_3 = log_call('hi')(plus_plus, 2, 3, 4)

result_4 = log_call('hi')(double, val=1)

print(result_1)
print(result_2)
print(result_3)
print(result_4)

mypy выход:

test.py:26: error: Need type annotation for 'result_1'
test.py:27: error: Need type annotation for 'result_2'
test.py:28: error: Need type annotation for 'result_3'
test.py:30: error: Need type annotation for 'result_4'
test.py:32: error: Cannot determine type of 'result_1'
test.py:33: error: Cannot determine type of 'result_2'
test.py:34: error: Cannot determine type of 'result_3'
test.py:35: error: Cannot determine type of 'result_4'

Теперь вместо добавления аннотаций типа к переменным result* я бы хотел настроить аннотацию типа функции, чтобы можно было выводить остальные. Это моя попытка:

from typing import Any, Callable, TypeVar

TypeT = TypeVar('TypeT')


def log_call(msg: str) -> Callable[[Callable[..., TypeT], Any, Any], TypeT]:
    def do_call(func: Callable[..., TypeT], *args: Any, **kwargs: Any) -> TypeT:
        print(msg)
        return func(*args, **kwargs)

    return do_call


def double(val: int) -> int:
    return 2 * val


def plus(a: int, b: int) -> int:
    return a + b


def plus_plus(a: int, b: int, c: int) -> int:
    return a + b + c


result_1 = log_call('hi')(double, 1)
result_2 = log_call('hi')(plus, 2, 3)
result_3 = log_call('hi')(plus_plus, 2, 3, 4)

result_4 = log_call('hi')(double, val=1)

print(result_1)
print(result_2)
print(result_3)
print(result_4)

Однако теперь количество параметров больше не подходит:

test.py:26: error: Too few arguments
test.py:28: error: Too many arguments
test.py:30: error: Unexpected keyword argument "val"

Наверное, я ищу что-то вроде

def log_call(msg: str) -> Callable[[Callable[..., TypeT], ...], TypeT]:

Но этот синтаксис недопустим.

Есть ли способ, которым я мог бы решить это?

...