Object appears to be sharing a dictionary

PMembrey
PMembrey used Ask the Experts™
on
Hi,

I've got an object that maintains a dictionary. It has a "get_or_create" method that accepts a string as a key. It then looks up the key in the dictionary and either returns a 'Store' object if it finds a match or creates one and returns that.

The idea is that I can request a Store object by passing a key and if it already exists I get that or it will simply create me a blank object.

The code for the StoreContainer looks like this:

class StoreContainer:
  stores{}

   def get_or_create_store(self,key):
        if key not in self.stores():
           self.stores[sc] = Store()
           self.stores[sc].id = key
       return(self.stores[sc])

Note: I don't have the exact code here so the indentation is approximate.

It seems to create all the stores fine but when I then add items to the stores, all the store items get it. I'm wondering if I'm just doing something obviously wrong - but I'm not sure what...

Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®

Author

Commented:
I've found that :

a =  main.get_or_create_store("test1")
b =  main.get_or_create_store("test2")

a is b
False

But :

a.stores is b.stores
True

Author

Commented:
Right, it seems like by default, any variables declared in the class are static. This was confusing as there are loads of posts on the web about how Python does not support static variables and yet it appears (to me at least) that it's doing precisely that.

By deleting the dictionary definition and using __init__  to create self.stores, it worked perfectly.

This URL helped me solve it:

http://paltman.com/2007/jul/08/python-classes-and-variable-gotchas-2/

For future reference, can any expert explain what's going on here?
Well, the original code in the question is not even syntactically correct.  It would be better to comment on that exact that did not work as details may be important for the expected and the observed behaviour.

Anyway, if the stores was initialized as stores = {} just below the class StoreContainer, then it is not a static variable of an object of the clas but a class variable.   It is shared by all objects of the class.

When you create an object of the class, the first time when you can get the reference to the object (and when you can access the data of that created instance) is inside the __init__() method.  It is passed to the __init__ as its first argument.

Unlike in compiled languages, data members are not fixed via the class definition.  You can create a no-member-data object and add the member data freely after the object was created.  This is what is usually done via __init__().

In other words, data members are not created (memory allocated) during construction of the object.  There is nothing like say C++ kind of constructor that you can define.  Instead, the __init__() is the first (but otherwise quite normal) method that is only implicitly called AFTER creation of the object.

I feel that you may need more details.  Feel free to ask until it will be clear ;)

Success in ‘20 With a Profitable Pricing Strategy

Do you wonder if your IT business is truly profitable or if you should raise your prices? Learn how to calculate your overhead burden using our free interactive tool and use it to determine the right price for your IT services. Start calculating Now!

Author

Commented:
Hi pepr,

After I moved it into the __init__ method, it worked fine. This is probably the first Python project I've worked on that required using multiple objects of the same type.

So to cut a long story short, if I define the dictionary as self.stores = {} in the __init__ method, everything will be okay? :-)

Author

Commented:
Although, if you could explain why doing:

qty_of_sales = 0
value_of_sales = None

in the class definition seems to work, that would be great :-)
I know it is confusing for those who worked only with classical compiled languages.  (I was also the one ;)

The key is to get acquainted with what Python variable really is.  At the beginning, study the following code that prints the following:

C:\tmp\___python\PMembrey\Q_25092961>a.py
__main__.MyClass
MyClass
['__module__', 'value_of_sales', '__doc__', 'qty_of_sales']
0
None
['objectVar']
['__doc__', '__module__', 'objectVar', 'qty_of_sales', 'value_of_sales']
0
3
1000
333
1000
class MyClass:
    '''This is the doc string of MyClass.'''
    qty_of_sales = 0           # class variable
    value_of_sales = None      # another class variable
    
    
a = MyClass()                  # create the instance of the class (i.e. the object)
a.objectVar = 3                # the object member variable (not in the class)

print a.__class__              # Reference to the class metaobject. When converted
                               # to string, it is displayed as the full identifier
                               # of the class.
print a.__class__.__name__     # bare name of the class
print a.__class__.__dict__.keys()  # the class internal dictionary of members
print a.__class__.qty_of_sales     # access explicitly the class variables
print a.__class__.value_of_sales

print a.__dict__.keys()            # the object internal dictionary of members

print dir(a)     # the built-in function dir() returs all accessible members,
                 # both class and object variable

print a.qty_of_sales    # access the class variable via the object
print a.objectVar       # this cannot be accessed via the class metaobject

b = MyClass()           # another instance of the same class

b.__class__.value_of_sales = 1000 # modify the class variable via the object
print a.value_of_sales  # the same value can be observed via the other object

b.value_of_sales = 333  # set (created first) the value of the instance variable
print b.value_of_sales  # now the instance variable is prefered

print a.value_of_sales  # the a still has access to the class variable

Open in new window

And yes. You should define all instance variables in the .__init__() method.  Better to say, you can define them any time in any method, but you must always write self.myvar.  Anyway, it is a good idea to define them in the __init__().

Do more with

Expert Office
Submit tech questions to Ask the Experts™ at any time to receive solutions, advice, and new ideas from leading industry professionals.

Start 7-Day Free Trial