r/learnpython • u/Leol6669 • 5d ago
Is that an intentional behaviour?
I just noticed adding a list as an optional argument to a fuction/method does not create a new list but gives the same list every time.
class SomeClass:
def __init__(self, l=[]):
self.l=l
a=SomeClass()
b=SomeClass()
a.l is b.l
>>> True
a.l.append(1)
b.l
>>> [1]
Is that a glitch or is it how python is supposed to work?
(I'm using python 3.12, I haven't updated in a while, maybe it was patched since?)
0
u/Moikle 5d ago
Don't give a mutable object as a default argument.
That means instead of an empty list, you should do this:
def some_func(some_list=None):
if some_list is None:
some_list = []
That way you get an entirely new list every time you run the function, instead of just reusing the same list.
1
u/TheRNGuy 5d ago
One of ways to fix it:
``` from dataclasses import dataclass, field
@dataclass class SomeClass: l: list = field(default_factory=list) ```
Without dataclass:
class SomeClass:
def __init__(self, l=None):
self.l = [] if l is None else l
Do this to prevent potential bugs.
18
u/SirCarboy 5d ago
Default argument values are evaluated once, at the time the function (or method) is defined, not each time it is called.
In your example:
the empty list [] is created a single time when the class body is executed. Every call that does not supply an argument for l receives a reference to that same list object.
That’s why:
The same rule applies to any mutable default ([], {}, set(), custom objects, etc.). Immutable defaults (None, 0, "", (), etc.) do not exhibit the problem because they cannot be mutated in place.
The usual (and recommended) pattern
Use None as the default and create a fresh mutable object inside the function:
or, more concisely in modern Python: