- Getting named arguments as dictionaries
- Passing named arguments using dictionaries
- Using keyword-only arguments
- Calling functions and the order of arguments
We can retrieve positional and named arguments in any number of *args
.
Getting named arguments as dictionaries
Only named arguments can be obtained as a dictionary, which allows you to store the names in keys:
def g(**kwargs):
return kwargs
g(x=1, y=2, z=None)
# {'x': 1, 'y': 2, 'z': None}
We can refer to an argument that receives this dictionary as kwargs
(keyword arguments).
We write the keyword arguments after all the usual positional ones:
*args
before the first argument with the default value**kwargs
after the last argument with the default value
Let us define a function that takes all kinds of arguments:
def f(x, y, *args, kx=None, ky=42, **kwargs):
return (x, y, args, kx, ky, kwargs)
f(1, 2, 3, 4, kx='a', ky='b', kz='c')
# (1, 2, (3, 4), 'a', 'b', {'kz': 'c'})
Do not worry. It is rare for a function to use all of these features in real-life code. Nevertheless, it is essential to understand how each type of argument declaration works and how to combine them.
Passing named arguments using dictionaries
As with positional arguments, named arguments can be passed to a function in bulk as a dictionary. To do this, you should put two asterisks before the dictionary. Here is an example:
def coords(x, y):
return (x, y)
coords(x=1, **{'y': 2})
# (1, 2)
As you can see, we also specified the regular named and wrapped arguments in a dictionary. It is both possible and convenient. Let us try to call the function f
from the example at the beginning of the lesson with two sets of arguments:
- The first one is for positional arguments
- The second one is for named ones
Here is the code:
positional = (2, 3)
named = dict(ky='b', kz='c')
f(1, *positional, 4, kx='a', **named)
# (1, 2, (3, 4), 'a', 'b', {'kz': 'c'})
Notice how we constructed the dictionary. We did not write a literal. So, the dictionary looks even more like a stored set of arguments because we called the dict
function with several named arguments.
You should also note that when replacing, these unfolding sets of arguments can be specified along with the corresponding type:
*positional
with positional arguments**named
with named ones
Moreover, any named arguments must come after any positional arguments.
Using keyword-only arguments
Python 3 added the ability to mark the named arguments. So, we can call functions by passing those arguments by name. We can refer to them as keyword-only arguments.
We cannot pass them to the function as positional arguments. Here is an example:
def open_file(name, *, writable=False, binary=False):
…
f1 = open_file('foo.txt', writable=True)
f2 = open_file('bar.bin', binary=True)
f3 = open_file('raw.dat', True, True)
# TypeError: `open_file()` takes 1 positional argument, but 3 were given
The *
separates ordinary arguments we can specify by name and position from strictly named arguments. This separator can only be used once in a single definition. And we cannot use it in functions with *args
.
It is not logical, but that is how it happened. You can declare functions that take only strictly named arguments, but you should put an asterisk at the beginning of the argument list.
This example shows a way to describe arguments. The first argument is the name of the file to open. The file name is always present because you need to open something. Moreover, we usually associate its meaning with the function name. Therefore, this argument cannot be named.
But writable
and binary
are optional arguments. Which also take the seemingly meaningless values True
and False
. We will not please many people with a call open_file('raw.dat', True, True)
. Therefore, we declare the options such we can only give them explicitly.
Calling functions and the order of arguments
When calling functions, we have more freedom to set the order. We can mix single-named arguments with substitutions for positional sets. Here is an example of such a call:
foo = [1, 2, 3]
bar = "abc"
# The function `f` is the same as in the first section of the lesson
f(kx=42, *foo, ky=100, *bar)
# (1, 2, (3, 'a', 'b', 'c'), 42, 100, {})
Let us talk about another feature. It is a function with a signature like f(x, *args)
where we cannot specify the x
argument by name and expand the parameter set simultaneously. You cannot do anything like this: f(*foo, x=42)
.
Are there any more questions? Ask them in the Discussion section.
The Hexlet support team or other students will answer you.
For full access to the course you need a professional subscription.
A professional subscription will give you full access to all Hexlet courses, projects and lifetime access to the theory of lessons learned. You can cancel your subscription at any time.