Python keyword only arguments

Python 3 got new feature called keyword-only arguments. Python has already a support for variables length positional arguments and variable length keyword arguments.

Jump to,

Current Syntax

By variable length positional arguments we can pass any number of positional arguments which are sucked up by a variable provided by syntax ” *varargs “. Also, by the syntax of variable length keyword arguments “*kwargs” we can pass any number of keyword arguments to function which are available as dictionary in the function.

def foo(a, b, *varargs, **kwargs):
print(a, b, varargs, kwargs)

## Call foo
foo(2, 9, 12, 34, x=3, name="bob")

Which outputs, the following. excluding 2, 9 all other positional arguments are sucked up by “vargars” and keywords are by “kwargs”

2 9 (12, 34) {'x': 3, 'name': 'bob'}

Existing syntax doesn’t allow us to use any kind of keyword arguments beyond variable length keyword arguments “**kwargs“.

You can choose to pass arguments by either position or it’s keyword.

One major limit for this syntax is that, all the regular arguments slots must be filled before the Variable Length keyword arguments slot.

Keyword-Only Arguments

This feature allows us to define a function to accept selected arguments by it’s keyword only. Which literally means you have to pass arguments to the function during function call by using it’s keyword only, otherwise it trows an exception. These keyword only arguments will never be automatically filled in by a positional argument.

How it’s useful

  • It improves the readability
  • API functions can accept the critical parameters as keyword only arguments to avoid ambiguity
  • You can create the function with all of it’s arguments as keyword only arguments
  • Functions with keyword only arguments are useful in selected use case scenarios when function is taking huge number of arguments

There are two kind of keyword only arguments. Which are,

  • Non-Default Keyword-Only Arguments
  • Default Keyword-Only Arguments

Non-Default Keyword-Only Arguments

Non-Default keyword-only arguments are keyword-only arguments without any defaults in function definition. If function is defined with non-default keyword-only arguments. Function should be called by passing corresponding arguments (with keywords). See the Syntax for Non-Default Keyword-Only Arguments

Default Keyword-Only Arguments

The name Default Keyword-Only Arguments is itself self explanatory. As it says, These are keyword-only arguments with defaults in the function definition

Keyword-Only Arguments Syntax

The syntax change is fairly very simple, it allows you to define keyword only arguments following variable length positional args *varargs .

def sortwords(*words,  case_sensitive=True):
. . .

Here the argument case_sensitive is keyword-only. Every positional arg you give goes to words argument. The argument case_sensitive is available as it’s default or should be passed by it’s keyword during function call

sortwords("bob", "jack", "rose",  case_sensitive=False)

Le’ts mix up regular positional, variable length positional and keyword-only arguments.

def add(a, b, *more, print_result=True):
...

According to above function definition, argument slots a and b are filled up first and then left over positional arguments are sucked up by argument more. Argument print_result will never be sucked up by vararg ‘more’. It can only be passed as keyword-only argument.

Let’s see the above function in action,

def add(a, b, *more, print_result=True):
result = a + b + sum(more)
if print_result:
print("sum of {} {} {} is {}".format(a, b, ' '.join(map(str, more)), result))
return result

Call above function

>>> add(1, 3, 9) 
sum of 1 3 9 is 13
13
>>> add(2, 9, 12, 3, print_result=False)
26
>>>

Here, did you notice ? the argument “more” will also suck up any erroneous positional arguments.

>>> add(9, 2, 5, 6, 'not sure why im here')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in add
TypeError: unsupported operand type(s) for +: 'int' and 'str'

Since we are performing addition, expected arguments are numbers but passing any other non compatible type causes error. In this case we might need to enforce arguments by it’s type or if you choose not to take or ignore varargs which brings us the following syntax “*” .

Let’s put all together,

def compute(a, b, c, *more, print_result=False, ignore_execeptions=True, **kwargs):
...

Let’s mix up all kind of arguments to see the kind of arguments, order and where these keyword-only arguments fit in the function definition.

Python Function Definition, Arguments Kind and Order
Python Function Definition, Arguments Kind and Order

Let’s see simple example in action to learn how we can use these arguments in combination with others.

def compute(a, b, c, print_args=True, intype=int,  *more, operation, print_result=False, return_type, ignore_exceptions=True, **kwargs):
if print_args:
print(a, b, c, print_args, intype, more, operation, print_result, return_type, ignore_exceptions, kwargs)
result = None
try:
arr = (a, b, c) + more
if operation == "count":
result = len(arr)
elif operation == "sum":
result = sum(arr)
else:
print("Unknow Operation")
raise NotImplementedError("Unknow Operation. Operation Not Implemented")
except:
import sys
print("Error performing operation: {}: {}".format(operation, sys.exc_info()))
if not ignore_exceptions:
raise
if print_result:
print("Result is: {}".format(result))
return result and return_type(result)

Above example may not be serving any logical purpose but intention was to show you the keyword-only arguments in action along with other argument types.

Keyword-Only Arguments with no varargs

Another syntax change is that, you can omit the name for the varargs argument to take keyword-only arguments and raise exception if any extra positional arguments are passed.

def compare(a, b, *, key=None):
. . .

Non-Default Keyword-Only Arguments Syntax

It is not necessary to provide a default value for keyword-only argument in the function definition

def compare(a, b, *, key):
. . .
>>>  compare(2, 3)   # missing non-default keyword-only arg
Traceback (most recent call last):
File "", line 1, in
TypeError: compare() missing 1 required keyword-only argument: 'key'

It trows TypeError exception if keyword-only argument is not passed in the function call. Since it is not having default value given.

Leave a Reply

Your email address will not be published. Required fields are marked *