b_su
b_su

Reputation: 31

python class attributes vs instance attributes

I have following code snippet:

class House:
    area = "Munich"

    def __init__(self, street, number):
        self.street = street
        self.num = number


h1 = House("Offenbachstarsse", 123)
h2 = House("Offenbachstarsse", 145)
print(h1.street + ',' + str(h1.num) + ',' + h1.area)
print(h2.street + ',' + str(h2.num)+ ',' + h2.area)

output ** Offenbachstarsse,123,Munich Offenbachstarsse,145,Munich **

h2.area = "Regensburg"
print(h1.street + ',' + str(h1.num) + ',' + h1.area)
print(h2.street + ',' + str(h2.num)+ ',' + h2.area)

output ** Offenbachstarsse,123,Munich Offenbachstarsse,145,Regensburg **

House.area = "Germany"
print(h1.street + ',' + str(h1.num) + ',' + h1.area)
print(h2.street + ',' + str(h2.num)+ ',' + h2.area)

output ** Offenbachstarsse,123,Germany Offenbachstarsse,145,Regensburg **

could someone please explain, how do updates to class attributes work? when an update to class attribute is done using the class, why does it only change the h1 object area and not h2 object area ?

I understand that the class attribute "area" when changed using the object, changes only the value of the class attribute of the used object i.e. h2.area ="Regensburg" updates only h2.area, whereas my expectation was that changes done in the class attribute using the class should be reflected in all the object instances as well. example: House.area = "Germany" would lead to h2.area = "Germany" and h1.area = "Germany". But I see that the h2.area is still showing the local update. Why is that ?

Upvotes: 1

Views: 112

Answers (1)

h4z3
h4z3

Reputation: 5458

When you did h2.area="Regensburg", you created an instance attribute of that name. Just like if you do h2.whatever=123 and it creates a new attribute. The class attribute is still there, just not directly accessible. Do del h2.area and then print(h2.area) and see for yourself!

Quick demonstration:

>>> class Test:
...   a = 1
... 
>>> t1 = Test()
>>> t2 = Test()
>>> t1.a = "this creates an instance attribute"
>>> t1.b = "just like this normally creates an instance attribute"
>>> t1.a
'this creates an instance attribute'

Now, let's check each object's dict dunder:

>>> t2.__dict__
{}
>>> t1.__dict__
{'a': 'this creates an instance attribute', 'b': 'just like this normally creates an instance attribute'}
>>> Test.__dict__
mappingproxy({'__module__': '__main__', 'a': 1, '__dict__': <attribute '__dict__' of 'Test' objects>, '__weakref__': <attribute '__weakref__' of 'Test' objects>, '__doc__': None})

As you can see, t1 has its own attributes stored. t2 doesn't - when we do t2.a, we don't find it so we check class attribute.

And now, for the big reveal:

>>> del t1.a
>>> t1.a
1
>>> t1.__dict__
{'b': 'just like this normally creates an instance attribute'}

We deleted the instance attribute, so we can again see the class attribute when we do t1.a

Upvotes: 1

Related Questions