Peter Smit
Peter Smit

Reputation: 28716

Why is dictionary in object not different from the other?

I have the following Python code:

#!/usr/bin/env python2.6

class container(object):
    name = 'container'
    configuration = {'var1': 'var1',
                     'var2': 'var2'}

if __name__ == "__main__":
    container1 = container()
    container2 = container()
    container2.name = 'container2'
    container2.configuration['var2'] = 'newvar2'

    print container1.name
    print container1.configuration['var2']

I expect this to print 'container' and 'var2', but for the latter it prints 'newvar2' instead

Why does the configuration variable point to the same dictionary for both objects? How can I fix this?

Most answers are already explaining that name and configuration are class variables. Why does the change of container2.name not influence container1.name?

Upvotes: 1

Views: 100

Answers (3)

aaronasterling
aaronasterling

Reputation: 71014

Because configuration is a class variable and not an instance variable. Fixing this should fix your problem.

class container(object):
    def __init__(self):
        self.name = 'container'

        self.configuration = {'var1': 'var1',
                             'var2': 'var2'}

What's going on here is that configuration ends up living in containter.__dict__ instead of in the dictionaries of its instances when you make it a class variable. This means that c.configuration is just accessing container.__dict__['configuration'] for all instances c.

For any class variable, an assignment of the form c.foo = x, creates an entry for foo in c.__dict__ which shadows its entry in container.__dict__. So a lookup will return that first. If you delete it, then a lookup will go back to retrieving the class instance. You could do

c = container()
c.configuration = x

and then c.configuration would be whatever x was. But inserting a key isn't an assignment, it's a method call on an existing object accessed through an existing binding.

You could get away with making name a class variable but if you want it to change from one instance to another then it should be an instance variable (unless you want a class wide default of course).

so:

  1. An assignment (using =, setattr or directly inserting in __dict__) on an instance will shadow a class variable. The class variable is still there.
  2. A lookup (calling a method, accessing the value) on an instance will grab an instance attribute if it exists and a class variable otherwise.

Upvotes: 3

khachik
khachik

Reputation: 28693

Because name and configuration are class or static members of the container class and they are shared for all the instances of container. Use self.name, self.configuration for instance variables:

class container(object):
   def __init__(self):
      self.name = "container"
      self.configuration = {}

Upvotes: 3

ceth
ceth

Reputation: 45295

self.name = 'container'
self.configuration = {'var1': 'var1',
                      'var2': 'var2'}

In init() if they are the class variables.

Upvotes: 0

Related Questions