Search code examples
pythonpython-3.xpython-class

Python class variable is shared with all instances


class list_class:
        def __init__(self, list_=[]):
                self.list_ = list_

        def add_item(self, item):
                self.list_ += [item]
>>> x = list_class()
>>> y = list_class()
>>> x.list_
[]
>>> y.list_
[]
>>> x.add_item(1)
>>> x.list_
[1]
>>> y.list_
[1]

Why does calling add_item() on x change the list_ variable on both instances?


Solution

  • Using list_=[] in a method argument is a bad Python idiom, for the reason you've discovered. Use the following instead:

    class ListClass:
        def __init__(self, list_=None):
            if list_ is None:
                list_ = []
            self.list_ = list_
    
        def add_item(self, item):
            self.list_.append(item)
    

    list_ is set to [] when __init__ is initially parsed. A list, however, is mutable, and not copied upon assignment. So when the __init__ method is run, each time, it uses the same initial list. With the above replacement, list_ is assigned to a new list every time __init__ is run, and the problem is circumvented. The same holds for a dict as a default for function argument value. It doesn't matter if the list or dict are empty or contain values (__init__(self, list_=[5]) would have had the same problem: don't use a mutable variable in a function argument as a default value.

    See the warning in the tutorial section of default function arguments.

    Other more Pythonic idioms are using CamelCase for class names, and using somelist.append(item) instead of somelist += [item].