Show how a Python class attribute is shared by every instance while an instance attribute is per-object.
An attribute defined in the class body belongs to the class and is shared by every instance. An attribute assigned to self belongs to that one object.
class Dog:
species = "canine" # class attribute
count = 0
def __init__(self, name):
self.name = name # instance attribute
Dog.count += 1
a = Dog("Rex")
b = Dog("Fido")
print(a.species, b.species) # canine canine
print(Dog.count) # 2 - shared by every instance
# Assigning on an instance shadows the class attribute
a.species = "puppy"
print(a.species) # puppy
print(b.species) # canine - untouched
print(Dog.species) # canine - untouchedThree different scopes are visible in that output. The name attribute lives on each instance separately. The species attribute was found on the class through both instances until a.species was assigned, at which point a got its own entry in its instance dictionary that shadows the class one. The count attribute was incremented on the class explicitly with Dog.count, so it stayed shared — but note that Dog.count += 1 inside a method reads the class attribute and writes back to the class, which is the standard way to keep a shared counter.
The lookup rule is the thing to state clearly: attribute access checks the instance dictionary first, then the class. That is why instance attributes shadow class attributes, and why deleting an instance attribute with del a.species makes the class attribute visible again.