Instance and Class Attributes
An instance attribute belongs to one object. A class attribute is defined on the class and can supply a default to its instances.
The diagram combines a class view, showing a definition, with object views, showing particular instances. In the Library box, underlining the member opening_hours marks a class-level value; name is an instance attribute. In an object box, the underlined header main : Library names that object and its class; the compartment below lists values stored on that instance. These are two uses of underlining: a class member is shared at class level, whereas an object header identifies a snapshot.
The class-attribute example below first uses 09:00–17:00, then changes the class default to 08:00–20:00; this overview shows the latter state. No opening_hours slot appears inside the two object boxes because they obtain that value by looking it up on Library.
Instance Attributes
class Library:
def __init__(self, name):
self.name = name
self.holdings = [] # instance attribute
central = Library("Central")
branch = Library("Neighborhood")
central.holdings.append("Hamlet")
print("Output:")
print(branch.holdings)Output
Output:
[]
Each branch receives a separate holdings list. Adding Hamlet to Central does not change the other branch.
Class Attributes
Run these examples in order. The new Library definition adds a class default:
class Library:
opening_hours = "09:00–17:00" # class attribute
def __init__(self, name):
self.name = name
main = Library("Central")
branch = Library("Neighborhood")
print("Output: ")
print(main.opening_hours)
print(branch.opening_hours)
Library.opening_hours = "08:00–20:00"
print(main.opening_hours)
print(branch.opening_hours)Output
Output:
09:00–17:00
09:00–17:00
08:00–20:00
08:00–20:00
Both instances initially read the class hours. Changing Library.opening_hours changes the default found by unshadowed instances.
Shadowing
Assigning the same name on an instance creates an instance-specific value.
Read the three boxes separately. Library still supplies the class default 08:00–20:00. The main object has no separate hours slot, so lookup reaches that default. The branch object now stores opening_hours = "10:00–18:00"; its own value is found first. This is shadowing: an instance value hides the same-named class value for that instance without changing the class or the other object.
branch.opening_hours = "10:00–18:00"
print("Output: ")
print(main.opening_hours)
print(branch.opening_hours)Output
Output:
08:00–20:00
10:00–18:00
Main still reads the class default; branch reads its own value. Changing the default again would not replace that branch-specific value.
Try it: change the class hours again and print both instances. Explain the different results. Avoid a mutable class list such as books = [] when every instance should own a separate collection.
The distinction between an instance and its class also guides where methods belong.