如何在指定* args或** kwargs的同时从函数字典运行函数 [英] How to run functions from a dict of functions while specifying *args or **kwargs

查看:67
本文介绍了如何在指定* args或** kwargs的同时从函数字典运行函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我基本上想运行从功能字典收集的任务。我在程序中使用了asyncio,但这对我的问题可能并不重要。这是我的代码来说明...

I basically want to run tasks that are gathered from a dict of functions. I'm using asyncio in my program but it probably doesn't matter for my question. Here is my code to illustrate...

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 函数添加了一些代码。

This works pretty well. But I want to repeat certain tasks periodically, so I added some code to the faketask function.

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。

This makes the function repeat by providing the kwarg interval with an integer. Future functions may also use additional *args and **kwargs.

所以我基本上希望我可以在任务列表字典中指定重复间隔,例如

So I basically wish I could specify the repeat interval in the tasklist dict, e.g.

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

但这不是无法正常工作,因为 faketask()缺少1个必需的位置参数:'taskname'。

But that doesn't work because faketask() is missing 1 required positional argument: 'taskname'.

有什么聪明的方法可以解决这个问题?

Is there any clever way to solve this?

作为奖励问题, _tasks.append(asyncio.ensure_future(tasklist [taskname](taskname)))看起来有点难看,有什么方法可以自动传递 taskname 参数吗?

And as a bonus question, the line _tasks.append(asyncio.ensure_future(tasklist[taskname](taskname))) looks a bit ugly, is there any way to pass the taskname argument automatically?

推荐答案

您可以使用 functools.partial ,它专门用于以下情况:

You can use functools.partial, which is designed exactly for situations like this:

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




作为奖励问题,行 _tasks.append(asyncio.ensure_future(tasklist [taskname](taskname))) 看起来有点丑陋,有没有办法自动传递taskname参数?

And as a bonus question, the line _tasks.append(asyncio.ensure_future(tasklist[taskname](taskname))) looks a bit ugly, is there any way to pass the taskname argument automatically?

您可以使用 items()删除冗余:

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

不需要显式调用 asyncio.ensure_future ,因为 asyncio.gather 会自动执行此操作。另外,我将 _tasks 重命名为 tasks 。按照惯例,变量名前面的 _ 表示该变量将不会在后续代码中使用,在这里不是这种情况。

The explicit call to asyncio.ensure_future is unnecessary because asyncio.gather does that automatically. Also, I've renamed _tasks to just tasks. By convention, the _ in front of a variable name denotes that the variable will not be used in subsequent code, which is not the case here.

这篇关于如何在指定* args或** kwargs的同时从函数字典运行函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆