You are setting an instance attribute, masking the class attribute:
d.kind = 'cat'
If you set it on the class instead it'll be visible on all instances:
Dog.kind = 'cat'
You cannot set class attributes by assigning to the name on instances. If you could, you would never be able to set instance attributes.
Use the vars()
function to see the difference:
>>> class Dog:
... kind = 'canine'
... def __init__(self, name):
... self.name = name
...
>>> d = Dog('Fido')
>>> e = Dog('Buddy')
>>> vars(d)
{'name': 'Fido'}
>>> 'kind' in vars(d)
False
>>> vars(Dog)
mappingproxy({'__module__': '__main__', '__dict__': <attribute '__dict__' of 'Dog' objects>, 'kind': 'canine', '__weakref__': <attribute '__weakref__' of 'Dog' objects>, '__doc__': None, '__init__': <function Dog.__init__ at 0x10084bbf8>})
>>> 'kind' in vars(Dog)
True
>>> d.kind
'canine'
>>> d.kind = 'cat'
>>> d.kind
'cat'
>>> vars(d)
{'name': 'Fido', 'kind': 'cat'}
>>> Dog.kind
'canine'
The vars()
function reveals the attributes available on both the class and one of the instances. By assigning to d.kind
, the new attribute appears in the dictionary of names for that instance, and from there on out all lookups on that instance will return that attribute and not fall through to the class.