Party Tricks: Empty List Expansion
Let’s say we’ve got a bunch of functions accessed through a dictionary, like this:
def f0():
return 0
def f1(a0):
return 0
def f2(a0, a1):
return 0
funcs = {
'f0': f0,
'f1': f1,
'f2': f2
}
We call these functions like this:
funcs['f0']()
Now assume we want to call these functions with user-provided arguments. Say, for example, that the user wants to call f1
with argument a
. They pass
the string 'f1 a'
. We might do something like
arg_str = 'f1 a'
args = args_str.split(' ')
funcs[args[0]](args[1])
Another user might want to call f2
with arguments a, b
. They pass the string 'f2 a b'
, and we do
args_str = 'f2 a b'
args = args_str.split(' ')
funcs[args[0]](args[1], args[2])
and so on.
If you know much Python, you’ll recognize this as a perfect use case for list expansion. Instead of explicitly passing each argument to the function, we can do
args_str = 'f2 a b'
args = args_str.split(' ')
funcs[args[0]](*args[1:])
The *
operator is the key. I won’t go too deep into the semantics, but there are lots of cool things you can do with
it.
In our use case, the operator replaces the list by pulling each element from it out into the list’s enclosing scope, in the order in which it appears in the list.
Syntactically, it does something like f(*[1, 2, 3]) -> f(1, 2, 3)
.
What I want to draw attention to today is how the *
operator reacts to empty lists (or more generally, empty iterables). Let’s go back to our example.
Let’s say we start with two variables, f
and args
. The former is a string containing the name of the function we want to call, and the latter is a
possibly empty list containing the arguments for the function.
We’d like to do
funcs[f](*args)
and have it work for all of our cases.
Clearly this will work in the case of f1
and f2
, but what about in the case of f0
? Well, I’m here to tell you that Python does the right thing and expands
the empty list into… nothing. Try running this:
def no_args():
return 0
x = []
print(no_args(*x))
It should print 0
with no complaints.
So that’s it, TLDR is that python does the right thing here.