Suppose I want to implement common variable among objects using class variables (similar to static in java/c++).
When I access class variable using object, it shows default value. Then I updaded class variable via object, its not updating class variable for other objects. It is showing old value in when class variable accessed via other objects or Class Name directly.
Why is it so, and what is the way in python to make class/static variable (common among objects)
# Class for Computer Science Student
class CSStudent:
stream = 'cse' # Class Variable
def __init__(self,name):
self.name = name # Instance Variable
# Objects of CSStudent class
a = CSStudent('Geek')
b = CSStudent('Nerd')
print(a.stream) # prints "cse"
print(b.stream) # prints "cse"
print(a.name) # prints "Geek"
print(b.name) # prints "Nerd"
# Class variables can be accessed using class
# name also
print(CSStudent.stream) # prints "cse"
# Now if we change the stream for just a it won't be changed for b
a.stream = 'ece'
b.stream = 'abc'
print(CSStudent.stream) # prints 'ece'
print(a.stream) # prints 'ece'
print(b.stream) # prints 'abc'
You need to know the lookup procedure.
First off, both instances and classes have their own namespaces. Only the class variables are shared between all instances. The namespace of classes and instances are accessible via __dict__
attribute.
When you access an attribute from an instance, Python first looks at the namespace of the instance, if it can find it, it returns it, otherwise it's gonna find it in its class!
class CSStudent:
stream = "cse"
a = CSStudent()
b = CSStudent()
print("stream" in a.__dict__) # False
print("stream" in b.__dict__) # False
print("stream" in CSStudent.__dict__) # True
print(a.stream) # cse
print(b.stream) # cse
So a
and b
doesn't have that stream
, only the class has.
Now a.stream = "something"
will add that attribute to the namespace of that specific instance.
a.stream = "something"
print("stream" in a.__dict__) # True
print("stream" in b.__dict__) # false
print("stream" in CSStudent.__dict__) # True
Now if you access a.stream
it finds it in the namespace of a
and returns it, but because b
doesn't have that, it will find it in the class.(the shared one)
print(a.stream) # something
print(b.stream) # cse
If you want to the change to reflect all instances, you need to change it on the class which has it shared between all instances.
class CSStudent:
stream = "cse"
a = CSStudent()
b = CSStudent()
print(a.stream) # cse
print(b.stream) # cse
CSStudent.stream = "something"
print(a.stream) # something
print(b.stream) # something
Always think about who has what. Then consider the precedence, instance namespaces are checked first.
Note: I simplified the explanation by not mentioning what descriptors are because we don't have one here. Take a look at it later. You would be surprised to see that in fact always class namespaces are checked first!