Python - how can I refer to a class variable or method from the __init__ method?

I have a hierarchy of objects in a python module as follows:

class BaseObject(object): initialized = False def __init__(self): self._initialize() @classmethod def _initialize(cls): print "cls.initialized = "+str(cls.initialized) if not cls.initialized: cls.x = 1 cls.initialized = True class ObjectOne(BaseObject): @classmethod def double_x(cls): cls.x = cls.x * 2 print cls.x class ObjectTwo(BaseObject): @classmethod def triple_x(cls): cls.x = cls.x * 3 print cls.x if __name__ == '__main__': obj_1 = ObjectOne() obj_1.double_x() obj_2 = ObjectTwo() obj_2.triple_x() 

When I run this module, I would like the output to be:

 cls.initialized = False 2 cls.initialized = True 6 

But I get:

 cls.initialized = False 2 cls.initialized = False 3 

What don’t I understand?

+4
source share
2 answers

You need to use the fully qualified class name to set the class variables. cls in double_x and tripple_x will refer to subclasses ( ObjectOne and ObjectTwo respectively), and attribute attributes in these subclasses will store new variables, and not change the variable of the BaseObject.x class. You can only change base class variables by accessing them directly.

Using your code, we get:

 >>> obj_1 = ObjectOne() cls.initialized = False >>> obj_1.double_x() 2 >>> obj_2 = ObjectTwo() cls.initialized = False >>> obj_2.triple_x() 3 >>> BaseObject.x Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: type object 'BaseObject' has no attribute 'x' >>> BaseObject.initialized, ObjectOne.initialized, ObjectOne.x, ObjectTwo.initialized, ObjectTwo.x (False, True, 2, True, 3) 

What happened in _initialize() , cls was set to ObjectOne or ObjectTwo , depending on which instance you created, and each subclass got its own copies of the initialized and x variables.

Using BaseObject._initialize() (to ensure that BaseObject initialized, not subclasses):

 >>> obj_1 = ObjectOne() cls.initialized = False >>> obj_1.double_x() 2 >>> obj_2 = ObjectTwo() cls.initialized = True >>> obj_2.triple_x() 3 >>> BaseObject.x, ObjectOne.x, ObjectTwo.x (1, 2, 3) >>> BaseObject.initialized True >>> 'x' in ObjectOne.__dict__ True >>> 'initialized' in ObjectOne.__dict__ False >>> 'initialized' in ObjectTwo.__dict__ False 

So now _initialize() used BaseObject as the target for setting the initialized and initial value for x , but double_x and triple_x still used their own subclasses to set the new value of x and did not pass that value through BaseObject .

The only parameter you must set for class variables in a specific base class is to refer to it directly in all class methods:

 class BaseObject(object): initialized = False def __init__(self): BaseObject._initialize() @classmethod def _initialize(cls): print "cls.initialized = "+str(cls.initialized) if not cls.initialized: cls.x = 1 cls.initialized = True class ObjectOne(BaseObject): @classmethod def double_x(cls): BaseObject.x = BaseObject.x * 2 print cls.x class ObjectTwo(BaseObject): @classmethod def triple_x(cls): BaseObject.x = BaseObject.x * 3 print cls.x 

which would give:

 >>> obj_1 = ObjectOne() cls.initialized = False >>> obj_1.double_x() 2 >>> obj_2 = ObjectTwo() cls.initialized = True >>> obj_2.triple_x() 6 

Note that I called BaseObject._initialize() so that cls a BasObject , not a subclass. Then, when setting up x , the double_x and triple_x methods still apply directly to BaseObject to make sure that the variable is set directly in the base class. When reading the value of x , the above example still uses cls , which uses the MRO class to search for x in the base class if it is not installed locally.

+7
source

You have two problems. First of all, to call the class method inside the class, you must use the COMPLETE name for the class: BaseObject._initialize() secondly, every time you create a new instance of ObjectOne or ObjectTwo , you overwrite BaseObject.x in your environment, so others use the initialized attribute x instead of the changed one. To fix this you should change two lines:

cls.x = cls.x * 2 To BaseObject.x = cls.x * 2

and

cls.x = cls.x * 3 To BaseObject.x = cls.x * 3

+1
source

All Articles