0

Under very simple circumstances, two objects can unintentionally share an attribute such as a list. Is there a reasoning behind this design choice of the language?

I define a class A with a list attribute children set by __init__ and empty by default. When I create two instances of A, they share the same empty list instead of two separate lists being created. Adding a child to one automatically adds it to the other as well.

class A:
    def __init__(self, children=[]):
        self.children = children

a1, a2 = A(), A()

print(a1, a1.children, id(a1.children))
print(a2, a2.children, id(a2.children))

Output:

<__main__.A object at 0x1023d9f28> [] 4331130696
<__main__.A object at 0x1023f6080> [] 4331130696

Both objects have the same empty list as children, instead of two separate empty lists, which is what I would expect. This can be realized e. g. like this:

class A:
    def __init__(self, children=None):
        if children is not None:
            self.children = children
        else:
            self.children = [] # creates a fresh new empty list each time

But having to write this boilerplate if-block defeats IMO the benefit of default argument values. Why does Python behave in this way and what is the most pythonic way to handle the situation?

bhbr
  • 101
  • 1
  • 1
    `self.children = children or []` if `0`, `''` etc are not valid values for `self.children` – DeepSpace Aug 04 '19 at 13:42
  • Thanks, this is exactly what stumped me, just in OOP form! The lesson I take home is to not use mutable objects as default values. They shouldn't be able to contain much state anyway, but rather be numbers, strings ar bools. – bhbr Aug 04 '19 at 13:46

0 Answers0