简体   繁体   中英

Python celery task canvas: SyntaxError: positional argument follows keyword argument

I have a chain of tasks that a celery worker runs. When a task is finished the chain carries forward the result of that task to the next task as a (positional) argument. Each task has it's own arguments + *args to handle the carried forward arguments. The problem is that I want to use keyword argument for the arguments of the task but those carried forward arguments are just positional arguments. The following code is just a simple example to show my problem without use of celery chains:

def test_func(data1,*args):
    print(data1, '\t', args)

def b():
    return {'data2':'b'}


test_func(data1='a', b())

I know that this generates "SyntaxError: positional argument follows keyword argument" because the first argument is using the argument name whereas the second one doesn't.

If I know how to properly return the result of function b() then my problem will be solved. That is, to return the result of b() in a way that b() is considered as a keyword argument when calling

test_func(data1='a', b())

UPDATE: It turned out celery chains carry over the results of each task to the first argument of the next task in the chain, not the last argument. This was my bad as I was new to celery chains. Therefore, I just switched the place of positional and keyword arguments in the function's header and my problem was solved as bellow:

def test_func(data1, data2):
    print(data1, '\t', data2)

def b():
    return 'b'


test_func(b(),data2='a')

As Python allows to have a keyword argument after a positional argument, everything turned out to be smoothly running.

Thanks to @MatiasCicero and @C.Nivs for their answers.

Change your test_func to:

def test_func(**kwargs):
    # kwargs is a dict containing the keyword arguments
    print(*kwargs)

Then, you can just do:

test_func(data1='a', **b())
# Same as doing test_func(data1='a', data2='b')

Change your function call to:

test_func('a', b())

Positional args always come first in function definitions and calls

In general, the order goes like so:

def myfunction(pos1, pos2, *args, **kwargs):
    # do things

where pos1 and pos2 are positional args. They have no default value.

*args is a list of non-keyword arguments, passed in like

myfunction(pos1, pos2, [1, '2', 333])

**kwargs is a dictionary of keyword arguments and they always go last:

myfunction(pos1, pos2, [1, '2', 333], {'key':'val'})

EDIT:

If you just get rid of the data1= in your function call, you should be fine

>>> test_func('a', b())
a    ({'data2': 'b'},)

If you need it to be unpacked, then:

def test_func(data_1, **kwargs):
    print(data_1, '\t', '\t'.join([kwargs[k] for k in kwargs.keys()]))

And you can unpack the results from b()

>>> test_func('a', **b())
a    b

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM