Как аннотировать функцию Python, чтобы намекнуть, что она принимает те же аргументы, что и другая функция? - PullRequest
6 голосов
/ 25 февраля 2020

Существует ли какой-либо синтаксис подсказки типа Python, указывающий, что функция принимает те же параметры (и типы параметров), что и другая функция? В частности, это полезно для переноса, например,

async def do_stuff(
        param1: str,
        param2: int,
        param3: int = 14,
):
    ...

def run_async_thing(*args, **kwargs):  # <--- What can I put here to say 'takes args like `do_stuff`'?
    return asyncio.get_event_loop().run_until_complete(do_stuff(*args, **kwargs))

. В этом случае я хотел бы добавить подсказку типа в функцию run_async_thing, чтобы определить, что она ожидает те же типы аргументов, что и do_stuff function.

Возможно ли это, и если да, то как?

Основная причина желания этого заключается в том, чтобы мои инструменты (в частности PyCharm / IntellliJ IDEA) могли выяснить, какие аргументы run_async_thing следует ожидать / принять. Если это помогает с документацией, это бонус, но это в основном для инструментов.

Ответы [ 3 ]

4 голосов
/ 27 февраля 2020

Определите параметры явно. Вы без необходимости обобщаете сигнатуру для run_async_thing:

def run_async_thing(p1: str, p2: int, p3: int):
    return asyncio.get_event_loop().run_until_complete(do_stuff(p1, p2, p3))

В более общем смысле вы можете run_async_thing взять один кортеж (или другой объект) в качестве аргумента. Например:

async def do_stuff(t: Tuple[str, int, int]):
    ...

def run_async_thing(args: Tuple[str, int, int]):
   return asyncio.get_event_loop().run_until_complete(do_stuff(args))

Тип кортежа может быть учтен:

StuffDoerArgs = Tuple[str, int, int]

async def do_stuff(t: StuffDoerArgs):
    ...

def run_async_thing(args: StuffDoerArgs):
    ...
1 голос
/ 27 февраля 2020

Вам необходимо определить типы параметров и возвращаемые типы. Затем вы можете скопировать __annotations__ из одной функции в другую.

Пример:

def abc(num: int, name: str) -> list:
    return [num, name]

print(abc.__annotations__)

Output: {'num': <class 'int'>, 'name': <class 'str'>, 'return': <class 'list'>}

Теперь мы создаем еще одну функцию:

def xyz(num, name):
    return [num, name]

print(xyz.__annotations__)

Output: {}

Вы можете просто скопировать вывод __annotations__ из одного в другой.

xyz.__annotations__ = abc.__annotations__

Так что теперь:

print(xyz.__annotations__)

Output: {'num': <class 'int'>, 'name': <class 'str'>, 'return': <class 'list'>}
0 голосов
/ 05 марта 2020

Если вы обнаружите, что постоянно используете набор параметров для различных функций, вы можете сгруппировать их с классом -

Вместо

async def do_stuff(
        param1: str,
        param2: int,
        param3: int,
):
    ...

def run_async_thing(p1: str, p2: int, p3: int):
    ...

Вы можете сделать

class AsyncArgs:
    def __init__(self, p1: str, p2: int, p3: int):
        self.p1 = p1
        self.p2 = p2
        self.p3 = p3

    def get_p1(self):
        return self.p1

    def get_p2(self):
        return self.p2

    def get_p3(self):
        return self.p3

async def do_stuff(args: AsyncArgs):
    ...

def run_async_thing(args: AsyncArgs):
    ...
...