Friday, December 4, 2020

Python Morsels: Accepting Arbitrary Keyword Arguments

Related article:

Transcript:

Let's make a function that accepts arbitrary keyword arguments.

Calling With Arbitrary Keyword Arguments

We're going to make a function called say_things that we can call with Trey, ducks=2, cup=1 in order to print out, Trey has... 2 ducks, 1 cup, That's all!. It should work like this:

>>> say_things("Trey", ducks=2)
Trey has...
  2 ducks
That's all!

We'll start with a function that accepts a name argument only:

>>> def say_things(name):
...     print(f"{name} has...")
...     print("That's all!")
...

We can't call this function with the keyword arguments ducks=2 and cup=1 because we will get an error:

>>> say_things("Trey", ducks=2, cup=1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: say_things() got an unexpected keyword argument 'ducks'

Capturing Arbitrary Keyword Arguments

In order to accept any keyword arguments given to this function, we need to use the ** operator. In our function definition we'll put ** and a variable name (things in our case) to tell Python that this function should accept any keyword argument given to it and it should store them in a dictionary which that variable name (things) will point to:

>>> def say_things(name, **things):
...     print(f"{name} has...")
...     print("That's all!")
...

When our say_things function is called, the keys in the things dictionary will be the keyword argument names given (ducks and cup in the aspirational example above) and the values will be the values that were given to those arguments (2 and 1).

To loop over this dictionary, we'll use the items method to get tuples of key-value pairs:

>>> def say_things(name, **things):
...     print(f"{name} has...")
...     for name, count in things.items():
...         print(f"  {count} {name}")
...     print("That's all!")
...

So this new function should accept our name argument and any keyword arguments given to it. For example passing ducks=2 print out 2 ducks:

>>> say_things("Trey", ducks=2)
Trey has...
  2 ducks
That's all!

If we say cup=1 and ideas=3 we'll see those printed out too:

>>> say_things("Trey", ducks=2, cup=1, ideas=3)
Trey has...
  2 ducks
  1 cup
  3 ideas
That's all!

This all works because of **, which is capturing any keyword arguments given to this function into a dictionary.

Arbitrary Keyword Arguments in Python Library

You don't really see ** used that often. This operator is most often used with class inheritance in Python, where you're capturing any arguments given to your class and passing them up to some parent class.

However, there is one method on one of the built-in types in Python that uses **: the string format method.

>>> "{n} {item}".format(n=3, item="ducks")
3 ducks

The format method doesn't just accept n and item arguments, it accepts any keyword arguments we can think of to give it. We can see that by looking at the documentation for the format method:

>>> help(str.format)

Help on method_descriptor:

format(...)
    S.format(*args, **kwargs) -> str

You can see that the string format method accepts *args and **kwargs. It's capturing all positional arguments and all keyword arguments given to it. So the format method can accept any arguments you give to it.

Summary

If you need to write a function that accepts arbitrary keyword arguments, you can use the ** operator in your function definition.



from Planet Python
via read more

No comments:

Post a Comment

TestDriven.io: Working with Static and Media Files in Django

This article looks at how to work with static and media files in a Django project, locally and in production. from Planet Python via read...