Tutorial :Python Module/Class Variable Bleeding



Question:

Okay, it took me a little while to narrow down this problem, but it appears python is doing this one purpose. Can someone explain why this is happening and what I can do to fix this?

File: library/testModule.py

class testClass:        myvars = dict()        def __getattr__(self, k):          if self.myvars.has_key(k):              return self.myvars[k]        def __setattr__(self, k, v):          self.myvars[k] = v        def __str__(self):          l = []          for k, v in self.myvars.iteritems():              l.append(str(k) + ":" + str(v))            return " - ".join(l)  

test.py

from library import testModule    #I get the same result if I instantiate both classes one after another  c1 = testClass()  c1.foo = "hello"  c2 = testClass()    print("c1: " + str(c1) + "\n")  print("c2: " + str(c2) + "\n")  

Output:

c1: foo:hello  c2: foo:hello  

My best guess is that because library has an "__init__.py" file, the whole module is loaded like a class object and it's now become part of a lasting object.. is this the case?


Solution:1

myvars is a property of the class, not the instance. This means that when you insert an attribute into myvars from the instance c1, the attribute gets associated with the class testClass, not the instance c1 specifically. Since c2 is an instance of the same class, it also has the same attribute.

You could get the behavior you want by writing this:

class testClass:      def __init__(self):          self.myvars = dict()        def __getattr__(self, k):          if self.myvars.has_key(k):              return self.myvars[k]        def __setattr__(self, k, v):          self.myvars[k] = v        def __str__(self):          l = []          for k, v in self.myvars.iteritems():              l.append(str(k) + ":" + str(v))          return " - ".join(l)  


Solution:2

The other answers are correct and to the point. Let me address some of what I think your misconceptions are.

My best guess is that because library has an "__init__.py" file, the whole module is loaded like a class object and it's now become part of a lasting object.. is this the case?

All packages have an __init__.py file. It is necessary to make something a python package. That package may or may not have any code in it. If it does it is guaranteed to execute. In the general case, this doesn't have anything to do with how the other modules in the package are executed, although it certainly is possible to put a lot of really cool trickery in there that does affect it.

As for how modules and classes work, it is often a really good idea to think of a module as a class object that gets instantiated once. The loader executes the files once and all variables, class definitions, and function definitions that are available at the end of the file are then accessible as part of the module.

The same is true of classes, with the main exception that functions declared within classes are transformed into methods (and one special method let's you instantiate the class). So testModule has-a testClass has-a myvars. All three objects are unique: there will not be multiple instances of any of them. And the has-a relathionship is really more-or-less the same whether we say "module has-a class object" or "class object has-a class variable". (The difference being implementation details that you ought not be concerned with.)


Solution:3

For a good reference on how to use getattr and other methods like it, refer to How-To Guide for Descriptors and there's nothing like practice!


Note:If u also have question or solution just comment us below or mail us on toontricks1994@gmail.com
Previous
Next Post »