multiprocess.apply_async How do I wrap *args and **kwargs?

keyword-argument, multiprocessing, python

Solution

You don't have to use `*` and `**` explicitly. Simply pass the tuple and the dict and let `apply_async` unpack them:

from multiprocessing import Pool

def f(x, *args, **kwargs):
    print x, args, kwargs

args, kw = (1,2,3), {'cat': 'dog'}

print "# Normal call"
f(0, *args, **kw)

print "# Multicall"
P = Pool()
sol = [P.apply_async(f, (x,) + args, kw) for x in range(2)]
P.close()
P.join()

for s in sol: s.get()

Output:

# Normal call                                                                                        
0 (1, 2, 3) {'cat': 'dog'}
# Multicall
0 (1, 2, 3) {'cat': 'dog'}
1 (1, 2, 3) {'cat': 'dog'}

Remember that in python's documentation, if a function accepts `*args` and `**kwargs` its signature explicitly states that:

the_function(a,b,c,d, *args, **kwargs)

In your case:

apply_async(func[, args[, kwds[, callback]]])

There are no `*` there, hence `args` is one argument, which is unpacked when calling `func` and `kwargs` is one argument and processed in the same way. Also note that it's not possible to have other arguments after `**kwargs`:

>>> def test(**kwargs, something=True): pass

  File "<stdin>", line 1
    def test(**kwargs, something=True): pass
                     ^
SyntaxError: invalid syntax

Problem

I'm trying to get `multiprocess.apply_async` to take in both `*args` and `**kwargs`. The docs indicate that this might be possible with the calling sequence: ``` apply_async(func[, args[, kwds[, callback]]]) ``` But I can not figure out how to get the calling syntax correct. With the minimal example: ``` from multiprocessing import Pool def f(x, *args, **kwargs): print x, args, kwargs args, kw = (), {} print "# Normal call" f(0, *args, **kw) print "# Multicall" P = Pool() sol = [P.apply_async(f, (x,), *args, **kw) for x in range(2)] P.close() P.join() for s in sol: s.get() ``` This works as expected giving the output ``` # Normal call 0 () {} # Multicall 0 () {} 1 () {} ``` When args is not an empty tuple, for example `args = (1,2,3)`, the single call works, but the multiprocessing solution gives: ``` # Normal call 0 (1, 2, 3) {} # Multicall Traceback (most recent call last): File "kw.py", line 16, in <module> sol = [P.apply_async(f, (x,), *args, **kw) for x in range(2)] TypeError: apply_async() takes at most 5 arguments (6 given) ``` With the kwargs argument I get, for example `kw = {'cat':'dog'}` ``` # Normal call 0 () {'cat': 'dog'} # Multicall Traceback (most recent call last): File "kw.py", line 15, in <module> sol = [P.apply_async(f, (x,), *args, **kw) for x in range(2)] TypeError: apply_async() got an unexpected keyword argument 'cat' ``` How do I properly wrap `multiprocess.apply_async`?

Original source