Python Programming from First Principles: Learn to Code, Think Computationally, and Solve Real-World Problems
PDFEPUB
BOOK 000 · CHAPTER 7 · Instance and Class Attributes

Instance and Class Attributes

On this pageInstance AttributesClass AttributesShadowing

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.

Library+opening_hours = "08:00-20:00"+namemain : Libraryname = "Central"branch : Libraryname = "Neighborhood"

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)
Listing 289 — Instance Attributes

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)
Listing 290 — Class Attributes

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.

Library+opening_hours = "08:00-20:00"main : Libraryname = "Central"branch : Libraryname = "Neighborhood"opening_hours = "10:00-18:00"
branch.opening_hours = "10:00–18:00"

print("Output: ")
print(main.opening_hours)
print(branch.opening_hours)
Listing 291 — Shadowing

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.