Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

python not accept keyword arguments

I am trying to make my code NOT to accept keyword arguments just like some bulitins also do not accept keyword arguments, but, I am unable to do so. Here, is my thinking according to my limited understanding:-

def somefunc(a,b):
    print a,b

somefunc(10,20)

Output:

10 20

Now, When I run the following (I know this is not expected to be keyword argument in the function definition, but, looking at the function call, it seems to be the same syntax as that of when calling a function which accepts keyword arguments):

somefunc(b=10,a=20)

Output:

20 10

I have 2 questions:-

  1. Looking at the function call somefunc(b=10,a=20) and not the function definition, this can seem to be either of a call to a function which accepts just normal arguments or a function which accepts keyword arguments. How does the interpreter differentiate between the two?
  2. Is it possible to convert any of our function in a form so that it does not accept keyword arguments just like many of the builtins do?

Why I want to do this at all? I am just checking if I can do this, so that I do not miss anything in understanding python in depth. I do knot know whether python allows that or not.

like image 851
GodMan Avatar asked Sep 08 '12 18:09

GodMan


4 Answers

You can use arbitrary argument lists to do this. See http://docs.python.org/tutorial/controlflow.html#arbitrary-argument-lists

For example:

def somefunc(*args):
    print args[0], args[1]

Calling without keywords:

somefunc(10,20)

Gives:

10 20

Calling with keywords:

somefunc(a=10,b=20)

Gives an error:

TypeError: someFunc() got an unexpected keyword argument 'a'

It's unclear why you would want to do this though.

like image 81
mkayala Avatar answered Sep 21 '22 11:09

mkayala


ad 1) Correct names are verified automatically by Python if they are called like somefunct(name=value, ...). I need not to remember the exact standard order of parameters and to verify it too "neurotic" by looking into the documentation every month at every usage, if I remember a function with nice descriptive names of parameters and it will be tested that they are accepted by Python. On the contrary, the correct order of used parameters can be verified only by documentation. Calling by named parameters is preferred over very long list of positional parameters. Therefore the reported behaviour is well-founded. (Short single letter parameters "a, b" don't help against mistakes of course.)

ad 2) Some well known builtin fast functions written in C with small fixed number of required parameters do not support calling with named parameters. (e.g. hasattr)

This is because they use only simple header ...(... PyObject *args) and therefore all named parameters are rejected automatically. (Python can never introspect into names of arguments in C source. :-)

Many other C functions have a header ...(... PyObject *args, PyObject *kwds) and they support exact list of names explicitely by implementing much more complicated validation PyArg_ParseTupleAndKeywords and by writing the names to docs strings.


Edit: Positional-only parameters are possible in Python 3.8 by a new function parameter syntax / to indicate that some function parameters must be specified positionally and cannot be used as keyword arguments.

def somefunc(a, b, /):
    print(a, b)
like image 22
hynekcer Avatar answered Sep 20 '22 11:09

hynekcer


Looking at the function call somefunc(b=10,a=20) and not the function definition, this can seem to be either of a call to a function which accepts just normal arguments or a function which accepts keyword arguments. How does the interpreter differentiate between the two?

Not sure if this is quite what you're asking, but if I understand you right, the answer is "it doesn't". You can call the function with keywords no matter how the arguments are defined in the function. If you pass any arguments using keyword syntax (e.g., f(a=...)), Python binds the corresponding values to the arguments with the same names in the function definition. It doesn't matter whether a default value was defined. The two kinds of function definition don't create different "kinds" of arguments, it's just that some of the arguments might have default values and others might not. So whether you do def f(a) or def f(a=2), you can still do f(a=...). The only restriction is that you have to pass/define positional arguments first (e.g., you can't do def f(a=2, b) or f(a=2, 3)). See also this answer.

As for the second part of your question, I'm not aware of any way to stop a Python function from accepting keyword-passed values for named arguments. If you define only *args then it won't accept keyword arguments, but the positional arguments can't have separate names.

like image 44
BrenBarn Avatar answered Sep 20 '22 11:09

BrenBarn


There isn't such a strong distinction in Python between keyword and positional arguments. In fact, it is as simple as:

Positional arguments are parsed in the order they are listed in the function call Keyword arguments can be added in any order, but cannot come before positional arguments.

So, if you have this:

def foo(x):
    pass

You can do:

foo(1) # positional
foo(x=1) # keyword

But you cannot do foo() because you didn't supply a default value.

Similarly, if you have this:

def foo(x,y='hello'):
    pass

foo(1) # this works fine
foo() # this is invalid, as an argument without a default isn't passed
foo(y='hello',1) # error - positional arguments come before keyword arguments

Don't forget to read up on arbitrary argument lists.

like image 33
Burhan Khalid Avatar answered Sep 21 '22 11:09

Burhan Khalid