22

Possible Duplicate:
“Least Astonishment” in Python: The Mutable Default Argument

I'm very confused about the behavior of dictionaries as class instance variables in Python 3. The way I understand it, instance variables in Python have per-instance storage, unlike class variables which are per-class (similar to what some other languages call "static").

And this seems to hold true, except when the instance variable is a dictionary created from a default parameter. For example:

class Foo:
    def __init__(self, values = dict()):
        self.values = values

f1 = Foo()
f1.values["hello"] = "world"

f2 = Foo()
print(f2.values)

This program outputs:

{'hello': 'world'}

Huh? Why does the instance f2 have the same dictionary instance as f1?

I get the expected behavior if I don't pass in an empty dictionary as a default parameter, and just assign self.values to an empty dictionary explicitly:

class Foo:
    def __init__(self):
        self.values = dict()

But I can't see why this should make any difference.

2
  • 1
    It might be that the default parameters are only evaluated once, when the class is loaded. That way you're merely assigning the same reference as a default parameter. Commented May 16, 2011 at 17:28
  • Stack overflow has a nice "FAQ" function per tag. Here is the FAQ for the Python tag: stackoverflow.com/questions/tagged/… Your question is answered in question number 4. Commented May 16, 2011 at 18:30

2 Answers 2

19

This is a well known surprise in Python. The default parameters are evaluated when the function is defined, not when it is called. So your default parameter is a reference to a common dict. It has nothing to do with assigning it to class/instance variables.

If you want to use a default parameter, use None, and check it:

if values is None:
    self.values = {}
else:
    self.values = values
Sign up to request clarification or add additional context in comments.

2 Comments

You'll get the same behavior with a list as well
You get the same behaviour with every single mutable object.
3

Default values are only evaluated once. You want something like this:

 class Foo:
     def __init__(self, values = None):
         self.values = values or dict()

If you supply a values, that'll get used. If not, values is evaluated as FALSE by the or operator and instantiates a new dict.

1 Comment

This failes if anything falsy is passed as values - e.g. an empty instance of a custom dict subclass.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.