optional list argument "list = list or []" in python
Asked Answered
C

3

5

Conventional way of dealing with optional list arguments is the following:

def func(list_of_vals = None):
   if list_of_vals is None:
      list_of_vals = []
   ...

I wounder if the following (shorter) version has any pitfalls? why nobody do that? is it considered more obscure?

list_of_vals = list_of_vals or []
Climax answered 28/10, 2016 at 21:36 Comment(8)
I do that, I think it's great. Decent python programmers will understand it. But using l as a variable name, that's bad.Icy
@AlexHall , sure, that's just a sample piece of code to illustrate an ideaClimax
If someone explicitly passes an empty list, you create a new one. That may not be what they were expecting.Configurationism
This is very common. It's standard in JS as well. In fact, default arguments in Typescript compile into the above code, but in JS. Anyone even remotely proficient in the language will know exactly what you're doing.Grouchy
@Configurationism The fact that an empty list in Python is falsely kind of throws a wrench in the pattern unfortunately.Grouchy
@Configurationism It would only be an issue if the function is supposed to modify its input list in place. But if that's what the function does, it doesn't make sense for the argument to be optional.Martin
@Martin yes, if they're also following the "either mutate or return" pattern it should be fineConfigurationism
@Configurationism that is a great comment, you might want to put it as answer so that more people see itClimax
M
9

The pattern if arg is None: is usual, it is familiar to Python developers and has no weird edge cases. My recommendation is just stick with the convention.

Your proposal using or logically deviates when bool(list_of_vals) == False but list_of_vals is not None, so I would recommend against doing that.

Another possible option is to "duck type" using an empty tuple:

def a(vals=()):
    ...

Because tuples are immutable, this has none of the pitfalls of the mutable default list. There are many use-cases where you only need to the input container to be indexable and iterable, so vals can happily remain as a tuple.

Millihenry answered 28/10, 2016 at 21:39 Comment(5)
I feel like if type of typical values passed to function (list) differs from default value type (tuple), that might be even more misleadingClimax
This is an excellent idea. It won't work if the passed list is expected to be modified by the function (which would be strange for an optional argument), but otherwise it even suggests the immutability which is a plus.Mcentire
@BenUsman A good Python function should care about the type of the argument as little as possible anyway.Mcentire
vals = vals if vals is not None else [] might be somewhere in between? (both short, readable and conventional)Climax
"A good Python function should care about the type of the argument as little as possible anyway" ... unless it needs to do anything with the argument, and then it should care very much if it's an appropriate type to do it with :PDerayne
L
1

There are two cases, you want that the list can be altered outside the function, then the second variant prevents calling a with:

some_list = []
a(some_list)
print(some_list)

If you want to prevent alternation of the list parameter, you should make a copy inside a

def a(l=()):
    l = list(l)
Leflore answered 28/10, 2016 at 21:42 Comment(0)
B
0

For the reasons mentioned in other comments, an input empty list can be confused with None, I would just do:

list_of_vals = [] if list_of_vals is None else list_of_vals

slightly more verbose but still a one-liner

Boondoggle answered 3/10, 2024 at 21:12 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.