Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python: Dictionary as instance variable [duplicate]

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.

like image 601
Channel72 Avatar asked May 16 '11 17:05

Channel72


People also ask

Can I assign a dictionary as a variable Python?

You can assign a dictionary value to a variable in Python using the access operator [].

How can you create a copy of a dictionary?

The dict. copy() method returns a shallow copy of the dictionary. The dictionary can also be copied using the = operator, which points to the same object as the original. So if any change is made in the copied dictionary will also reflect in the original dictionary.

How can you create a copy of a dictionary modifying the copy should not change the original )?

Use a for loop If you change this copy of the dictionary, it will not change the original dictionary. However, if one of the elements is an iterable object and a change is made to that element in the shallow copy, the same change will be reflected in the original copy.

What are the ways to copy a dictionary d2 to d1?

Copy a dictionary with a for loop To copy a dictionary it is also possible to use a for loop: >>> d1 = {'a':1,'b':2} >>> d2 = {} >>> for key in d1: ... d2[key] = d1[key] ...


2 Answers

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
like image 122
Thomas K Avatar answered Oct 25 '22 10:10

Thomas K


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.

like image 38
eduffy Avatar answered Oct 25 '22 11:10

eduffy