python class attribute
i have a question about class attribute in python.
class base :
def __init__ (self):
pass
derived_val = 1
t1 = base()
t2 = base()
t2.derived_val +=1
t2.__class__.derived_val +=2
print t2.derived_val # its value is 2
print t2.__class__.derived_val # its value is 3
The results are different. I also use id()
function to find t2.derived_val
and t2.__class__.derived_val
have different memory address.
My problem is derived_val
is class attribute. Why it is different in above example?
Is it because the instance of class copy its own derived_val
beside the class attribute?
Solution 1:
There are class attributes, and instance attributes. When you say
class base :
derived_val = 1
You are defining a class attribute. derived_val
becomes a key in
base.__dict__
.
t2=base()
print(base.__dict__)
# {'derived_val': 1, '__module__': '__main__', '__doc__': None}
print(t2.__dict__)
# {}
When you say t2.derived_val
Python tries to find 'derived_val' in t2.__dict__
. Since it is not there, it looks if there is a 'derived_val'
key in any of t2
's base classes.
print(t2.derived_val)
print(t2.__dict__)
# 1
# {}
But when you assign a value to t2.derived_val
, you are now adding an instance attribute to t2
. A derived_val
key is added to t2.__dict__
.
t2.derived_val = t2.derived_val+1
print(t2.derived_val)
print(t2.__dict__)
# 2
# {'derived_val': 2}
Note that at this point, there are two derived_val
attributes, but only
the instance attribute is easily accessible. The class attribute becomes accessible only through referencing base.derived_val
or direct access to the class dict base.__dict__
.
Solution 2:
Check it out here and here.
The __class__
attribute is the class that the object belongs to. So in your example, the situation is similar to static variables. The t2.__class__.derived_val
is referring to the variable that belongs to the class, not the variable that belongs to t2.
Solution 3:
Another way (perhaps a more concise one) to demonstrate this:
class A():
a1 = []
x = A()
y = A()
x.a1.append("test")
x.a1, y.a1
(['test'], ['test'])
class B():
b1 = None
def __init__(self):
self.b1 = list()
r = B()
s = B()
r.b1.append("test")
r.b1, s.b1
(["test"], [])