Как запускать функции из набора функций при указании * args или ** kwargs - PullRequest
0 голосов
/ 07 апреля 2019

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

import asyncio
import random


async def faketask(taskname):    # This is a function to simulate asynchronous tasks being performed.
    fakedelay = random.randint(1,6)
    print(f'{taskname} started (completing in {fakedelay} seconds)')
    await asyncio.sleep(fakedelay)
    print(f'{taskname} completed after {fakedelay} seconds')


async def main():
    tasklist = {    # This is a dict of tasks to be performed
    'Task-1': faketask,
    'Task-2': faketask,
    'Task-3': faketask,
    }

    _tasks = []
    for taskname in tasklist:
        _tasks.append(asyncio.ensure_future(tasklist[taskname](taskname)))
        print(f'Added {taskname} to job queue.')
    await asyncio.gather(*_tasks)


if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    loop.run_until_complete(main())
    loop.close()

Это работает довольно хорошо.Но я хочу периодически повторять определенные задачи, поэтому я добавил некоторый код в функцию faketask.

async def faketask(taskname, interval=None):
    fakedelay = random.randint(1,6)
    print(f'{taskname} started (completing in {fakedelay} seconds)')
    await asyncio.sleep(fakedelay)
    print(f'{taskname} completed after {fakedelay} seconds')
    if interval is not None:
        print(f'Repeating {taskname} in {interval} seconds')
        while True:
            await faketask(taskname, *args, **kwargs)
            await asyncio.sleep(interval)

Это повторяет функцию, предоставляя kwarg interval целое число.Будущие функции могут также использовать дополнительные * args и ** kwargs.

Поэтому я бы хотел указать интервал повторения в dict списка задач, например,

    tasklist = {
    'Task-1': faketask,
    'Task-2': faketask,
    'Task-3': faketask(interval=60),
    }

Но это не работаетпотому что faketask () отсутствует 1 обязательный позиционный аргумент: 'taskname'.

Есть ли какой-нибудь умный способ решить эту проблему?

И в качестве дополнительного вопроса, строка_tasks.append(asyncio.ensure_future(tasklist[taskname](taskname))) выглядит немного некрасиво, есть ли способ автоматически передать аргумент taskname?

1 Ответ

3 голосов
/ 07 апреля 2019

Вы можете использовать functools.partial, который предназначен именно для таких ситуаций:

'Task-3': functools.partial(faketask, interval=60),

И в качестве дополнительного вопроса строка _tasks.append(asyncio.ensure_future(tasklist[taskname](taskname))) выглядит несколько уродливо, есть ли способ автоматически передать аргумент имени задачи?

Вы можете использовать items() для удаления избыточности:

tasks = []
for taskname, taskfn in tasklist.items():
    tasks.append(taskfn(taskname))

Явный вызов asyncio.ensure_future не нужен, потому что asyncio.gather делает это автоматически. Также я переименовал _tasks в tasks. По соглашению, _ перед именем переменной означает, что переменная не будет использоваться в последующем коде, что здесь не так.

...