python positional args and keyword args

guoqiao picture guoqiao · Dec 13, 2011 · Viewed 7.2k times · Source

I am reading the source codes of mercurial, and found such a func def in commands.py:

def import_(ui, repo, patch1=None, *patches, **opts):
    ...

in python, postional args must be put ahead of keyword args. But here, patch1 is a keyword argument, followed by a positional argument *patches. why is this OK?

Answer

Abhijit picture Abhijit · Dec 13, 2011

Just have a look into the PEP 3102 also it seems its somehow related to this.

To summarize, patches and opts are there to accept variable arguments but the later is to accept keyword arguments. The keyword arguments are passed as a dictionary where as the variable positional arguments would be wrapped as tuples .

From your example

def import_(ui, repo, patch1=None, *patches, **opts):

Any positional parameters after u1,repo and patch1 would be wrapped as tuples in patches. Any keyword arguments following the variable positional arguments would be wrapped as Dictionary objects through opts.

Another important thing is that, the onus lies with the caller to ensure that the condition non-keyword arg after keyword arg is not violated.

So something that violates this would raise a syntax error..

For example

Calls like

 import_(1,2,3,test="test")
 import_(1,2,3,4,test="test")
 import_(1,2,3,4,5)
 import_(1,2,patch1=3,test="test")

are valid, but

import_(1,2,3,patch1=4,5)

would raise a syntax error SyntaxError: non-keyword arg after keyword arg

In the first valid case import_(1,2,3,test="test")

u1 = 1, repo = 2, patch1 = 3, patches = () and opts={"test":"test"}

In the second valid case import_(1,2,3,patch1=4,test="test")

u1 = 1, repo = 2, patch1 = 3 , patches = (4) and opts={"test":"test"}

In the third valid case import_(1,2,3,4,5)

u1 = 1, repo = 2, patch1 = 3 , patches=(4,5), and opts={}

In the fourth valid case import_(1,2,patch1=3,test="test")

u1 = 1, repo = 2, patch1 = 3 , patches=(), and opts={"test":"test"}
you can use patch1 as a keywords argument but doing so you cannot wrap any variable positional arguments within patches