What Is the Pythonic Way to Avoid Default Parameters That Are Empty Lists

What is the pythonic way to avoid default parameters that are empty lists?

def my_func(working_list=None):
if working_list is None:
working_list = []

# alternative:
# working_list = [] if working_list is None else working_list

working_list.append("a")
print(working_list)

The docs say you should use None as the default and explicitly test for it in the body of the function.

Most Pythonic way to convert None to an empty list in case a default argument is not passed in a Function?

You can check first if var (1 and 2) are Not None

def my_func(var1=None, var2=None):
var1 = var1 if var1 is not None else []
var2 = var2 if var2 is not None else []
if not isinstance(var1, list):
var1 = [var1]
if not isinstance(var2, list):
var2 = [var2]

return var1 + var2

This will cover many cases, such as :

print(my_func(var2=[1, 2, 3]))
print(my_func(var1=None,var2=[1, 2, 3]))
print(my_func(var1=0,var2=[1, 2, 3]))
print(my_func(var1=False,var2=[1, 2, 3]))
print(my_func(var1='',var2=[1, 2, 3]))


[1, 2, 3]                                                                                                                                                                                                                                       
[1, 2, 3]
[0, 1, 2, 3]
[False, 1, 2, 3]
['', 1, 2, 3]

Setting defaults for empty arguments (Python)

The first form as it reads easier. Without any specific context, you should explicitly test for the default value, to avoid potential truthiness issues with the passed in value.

def f(a, b=None):
if b is None:
b = []
pass

From PEP 8, Programming Recommendations:

Also, beware of writing if x when you really mean if x is not None --
e.g. when testing whether a variable or argument that defaults to None
was set to some other value. The other value might have a type (such
as a container) that could be false in a boolean context!

You can see examples of this approach throughout the cpython repository:

  • Lib/bdb.py
  • Lib/argparse.py
  • Lib/base64.py

How to type mutable default arguments

None is not the only sentinel available. You can choose your own list value to use as a sentinel, replacing it (rather than None) with a new empty list at run time.

_sentinel = []

def foo(bar: List[int]=_sentinel):
bar = [] if bar is _sentinel else bar
return sorted(bar)

As long as no one calls foo using _sentinel as an explicit argument, bar will always get a fresh empty list. In a call like foo([]), bar is _sentinel will be false: the two empty lists are not the same object, as the mutability of lists means that you cannot have a single empty list that always gets referenced by [].

How to stop function's list-type argument with default value from holding value on subsequent calls?

Default parameters are mutable in Python, you can think of them as belonging to the global scope. You want this:

def test(arg1=None):
if arg1 is None:
arg1 = []

arg1.append('bob')
return arg1

Default List Parameter doesn't Reset

No. It's a foible of Python that mutable object initializers do this. It's a better pattern to use None and set the initial value in the method body:

def f(a=None):
if a is None:
a = []
print(a)
a += [1]

If you use pylint, it provides a warning dangerous-default-value (W0102).

Why is the empty dictionary a dangerous default value in Python?

It's dangerous only if your function will modify the argument. If you modify a default argument, it will persist until the next call, so your "empty" dict will start to contain values on calls other than the first one.

Yes, using None is both safe and conventional in such cases.



Related Topics



Leave a reply



Submit