0% complete

Object-oriented Python and maintainable design · Lesson 1 of 3

Classes, objects, and instance state

Define a class when data and behavior form a useful object contract.

Lesson

1. Concept and mental model

A class defines behavior and structure; an instance is an object created from that class. The __init__ method initializes instance state, and self refers to the particular object being used. Instance attributes belong to each object, while class attributes are shared through the class unless shadowed. A mutable class attribute can unintentionally share data across all instances, so put per-instance lists or dictionaries on self during initialization.

2. How it works

Classes are useful when an object has a stable identity, meaningful state, and operations that belong together. They are not automatically better than simple functions or dictionaries. Start with the simplest representation that makes valid states and behavior clear. Use properties or methods to enforce invariants when callers should not modify an internal value arbitrarily.

3. Use it safely and effectively

Prefer composition when one object can use another object’s capabilities without inheriting its entire implementation. Inheritance expresses an “is-a” relationship and should preserve the expectations of the base type. Keep constructors predictable; avoid hidden network or file access inside __init__, because it makes object creation slow and hard to test. Practice by modeling a bank account that validates deposits and does not allow an invalid balance transition.

4. Syntax reference

class Counter:
    def __init__(self) -> None:
        self.value = 0

    def increment(self) -> int:
        self.value += 1
        return self.value

print(Counter().increment())

5. Guided walkthrough

Define the state each object owns, initialize it in __init__, and let methods operate on that instance through self. Create two objects with different values and verify that updating one does not unexpectedly change the other.

6. Common mistakes to avoid

  • Putting a mutable per-instance value on the class, which makes instances share the same object.
  • Using a class for a group of unrelated functions and data that do not need an object contract.

Visual guide

Create and use an object

  1. Step 01 Define

    Describe attributes and methods on a class.

  2. Step 02 Instantiate

    Initialize state for one object.

  3. Step 03 Operate

    Call methods that preserve its invariants.

Code examples

Worked example
PYTHON
class Counter:
    def __init__(self) -> None:
        self.value = 0

    def increment(self) -> int:
        self.value += 1
        return self.value

print(Counter().increment())
Expected output
1
Give each instance its own list
PYTHON
class Playlist:
    def __init__(self, name: str) -> None:
        self.name = name
        self.songs: list[str] = []

first = Playlist('Morning')
first.songs.append('Intro')
print(first.songs)
Expected output
['Intro']
Represent an object with a method
PYTHON
class Rectangle:
    def __init__(self, width: float, height: float) -> None:
        self.width = width
        self.height = height

    def area(self) -> float:
        return self.width * self.height

print(Rectangle(3, 4).area())
Expected output
12

Key points

  • Define a class when data and behavior form a useful object contract.
  • Prefer explicit, testable behavior over hidden side effects.
  • Validate assumptions at system boundaries and handle failure deliberately.

Check your understanding

Practice

Where should per-object mutable state normally be initialized?

Your learning progress

Finish this lesson