I have a question about __class__ in python.
The documentation says that __class__ is the class to which a class instance belongs. So I conducted a series of experiments:
class counter:
count = 0
def __init__(self):
self.__class__.count += 1
NewCounter1 = counter()
print NewCounter1.count #The result is 1
NewCounter2 = counter()
print NewCounter2.count #The result is 2
print NewCounter2.__class__.count is NewCounter2.count #result: True
Everything goes well.
Then I enter code as follows:
NewCounter2.__class__.count = 3
print NewCounter1.count #result:3
print NewCounter1.__class__.count #result:3
print NewCounter2.count #result:3
print NewCounter2.__class__.count #result:3
print NewCounter2.__class__.count is NewCounter2.count #result: True
From the code above, I thought that maybe NewCounter1.count equals NewCounter1, or __class__.count, but the following code surprised me:
NewCounter2.count = 5
print NewCounter1.count #result:3
print NewCounter1.__class__.count #result:3
print NewCounter2.count #result:5
print NewCounter2.__class__.count #result:3
print NewCounter2.__class__.count is NewCounter2.count #result: False
Why has NewCounter2.count changed but NewCounter2.__class__.count remained at 3? What’s more, when I changed NewCounter2.count, NewCounter2.__class__.count is NewCounter2.count became False. What in the world is the attribute __class__ ?
The problem is that at the moment of this sentence in your question, after the only instructions:
having created NewCounter1 and NewCounter2
and having modified the class attribute counter.count,
there are no objects NewCounter1.count nor NewCounter2.count in existence, and then “equals” has no real meaning.
.
See the creation of NewCounter1 and just after:
NewCounter._dict_ is the namespace of the instance NewCounter1
print NewCounter1.countprints the same asprint counter.countHowever, ‘count’ (the string ‘count’) isn’t in the namespace of NewCounter1, that is to say there is no attribute count in the namespace of the created instance !
How is it possible ?
That’s because the instance is created without assignement to a ‘count’ identifier inside the _init_
-> there is no real creation of any attribute as a field in NewCounter1, that is to say no creation of INSTANCE attribute.
The consequence is that when the instruction
print 'NewCounter1.count ==',NewCounter1.countis evaluated, the interpreter doesn’t find an instance attribute in the NewCounter1 ‘s namespace, and then goes to the class of the instance to search for the key ‘count’ in this class’s namespace; there it finds ‘count’ as a key of a CLASS attribute and can take the VALUE of the object counter.count as a VALUE to display in response to the instruction.
So,
NewCounter1.count equals NewCounter1.__class__.counthere means that the VALUE for NewCounter1.count, even if this one doesn’t really exist, is the VALUE of the class attribute NewCounter1. class.count. Here “is” is the english verb, not the feature is of the language that tests the identities of two objects, and it means ‘is considered to have ‘When
NewCounter2.__class__.count = 3is executed, only the class attribute counter.count is affected. The namespaces of NewCounter1 and NewCounter2 remain empty and the same mechanism of going to the class to find the value of counter.count is followed..
At the end, when
NewCounter2.count = 5is executed , this time an INSTANCE attribute count is created as a field in the NewCounter2 object and ‘count’ appears in the namespace of NewCounter2 .It doesn’t overwrite anything, because there was nothing preceding in the instance’s
__dict__No other change affects NewCounter1 and counter.count
The following code shows more explicitly the underlying events during execution:
result
.
An interesting thing to do is to add an instruction
self.count = counter.countBEFORE the line
self.__class__.count += 1 # <<=====to observe the changing of results
.
In conclusion, the point wasn’t concerning
__class__but the mechanism of searching an attribute , and this mechanism is misleading when ignored.