Objective

Implement classes, understand instance vs class attributes, use properties, inheritance, and abstract base classes.

Tools & Technologies

  • class
  • __init__
  • @property
  • @classmethod
  • @staticmethod
  • dataclass
  • abc

Key Commands

class MyClass:
@dataclass
@property
super().__init__()
from abc import ABC, abstractmethod

Architecture Overview

classDiagram class Animal { +name: str +sound: str +speak() str } class Dog { +breed: str +fetch() +speak() str } class Cat { +indoor: bool +purr() +speak() str } Animal <|-- Dog Animal <|-- Cat

Step-by-Step Process

01
Class Basics

Define a class with attributes and methods.

class BankAccount:
    interest_rate = 0.02  # class attribute

    def __init__(self, owner: str, balance: float = 0):
        self.owner = owner        # instance attribute
        self._balance = balance   # 'private' by convention

    @property
    def balance(self):
        return self._balance

    def deposit(self, amount: float):
        if amount <= 0:
            raise ValueError('Amount must be positive')
        self._balance += amount

    def __repr__(self):
        return f'BankAccount({self.owner!r}, {self._balance})'
02
Inheritance

Extend classes and override methods.

class SavingsAccount(BankAccount):
    def __init__(self, owner, balance=0, goal=None):
        super().__init__(owner, balance)  # call parent init
        self.goal = goal

    def deposit(self, amount):
        super().deposit(amount)  # call parent method
        if self.goal and self._balance >= self.goal:
            print(f'Goal of ${self.goal} reached!')

ac = SavingsAccount('Alice', goal=1000)
ac.deposit(1200)
03
dataclasses

Reduce boilerplate with @dataclass.

from dataclasses import dataclass, field

@dataclass
class Point:
    x: float
    y: float
    label: str = ''
    tags: list = field(default_factory=list)

    def distance_to(self, other: 'Point') -> float:
        return ((self.x-other.x)**2 + (self.y-other.y)**2)**0.5

p1 = Point(1.0, 2.0)
p2 = Point(4.0, 6.0)
print(p1.distance_to(p2))  # 5.0

Challenges & Solutions

  • Mutable default arguments in __init__ — use None and assign in body
  • Class attributes shared across all instances — modify carefully

Key Takeaways

  • @dataclass auto-generates __init__, __repr__, __eq__ — use for data containers
  • Use @property for computed attributes and validation without changing the interface