Welcome to Software Development on Codidact!
Will you help us build our independent community of developers helping developers? We're small and trying to grow. We welcome questions about all aspects of software development, from design to code to QA and more. Got questions? Got answers? Got code you'd like someone to review? Please join us.
Comments on Understanding mutable default arguments in Python
Parent
Understanding mutable default arguments in Python
Consider this code example:
def example(param=[]):
param.append('value')
print(param)
When example
is repeatedly called with an existing list, it repeatedly appends to the list, as one might expect:
example
is repeatedly called with an existing list, it repeatedly appends to the list, as one might expect:>>> my_list = []
>>> example(my_list)
['value']
>>> example(my_list)
['value', 'value']
>>> example(my_list)
['value', 'value', 'value']
>>> my_list
['value', 'value', 'value']
If it's called with an empty list each time, it seems that each empty list is considered separately, which also makes sense:
>>> example([])
['value']
>>> example([])
['value']
>>> example([])
['value']
However, if called without passing an argument - using the default - it seems to "accumulate" the appended values as if the same list were being reused:
>>> example()
['value']
>>> example()
['value', 'value']
>>> example()
['value', 'value', 'value']
Some IDEs will warn that param
is a "mutable default argument" and suggest changes.
Exactly what does "mutable default argument" mean, and what are the consequences of defining param
this way? How is this functionality implemented, and what is the design decision behind it? Is it ever useful? How can I avoid bugs caused this way - in particular, how can I make the function work with a new list each time?
Post
Everything you put on the line with def
is global (global to the file, not as in the global
keyword), so the (initially empty) list you create with param=[]
persists and gets reused between calls to example()
. You probably want to create a local list for each invocation instead. For that, you have to find a way to put param = []
inside the method.
The normal way is:
def example(param: list | None = None):
if param is None:
param = []
Python is powerful and fun, so you can come up with more pithy ways of doing it. However, you will then have to add comments for other people who don't expect it, and IDEs which don't understand them, so they will not be so pithy in the end. You're best off just using the normal way above.
I think other details are best addressed in separate questions, such as:
- Mutable vs. immutable in Python
- Implementation details of the interpreter
- The history of Python design decisions
- Why not just
def (param=None):
- Why not just
if param:
Please comment on this question if you do ask these separately, and want me to answer them.
2 comment threads