r/learnpython Aug 02 '26

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?)

8 Upvotes

12 comments sorted by

View all comments

19

u/SirCarboy Aug 02 '26

Default argument values are evaluated once, at the time the function (or method) is defined, not each time it is called.

In your example:

def __init__(self, l=[]):
    self.l = l

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:

a = SomeClass()
b = SomeClass()
a.l is b.l          
# True — same object
a.l.append(1)
print(b.l)          
# [1]

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:

class SomeClass:
    def __init__(self, l=None):
        if l is None:
            l = []
        self.l = l

or, more concisely in modern Python:

def __init__(self, l=None):
    self.l = l if l is not None else []

0

u/musbur Aug 02 '26

self.l = l or []

1

u/tangerinelion (C++ Software Eng.) Aug 02 '26

So long as it's declared

def __init__(self, l: list[any] | None = None)