Creating a User without a name makes no sense. The __init__ method is Python's constructor - it runs automatically when you create an object, letting you require and validate data from the start.

Basic constructor

Initialize objects with required data.

basic_init.py
# Basic __init__ Constructor

print("=== Basic Constructor ===\n")

class Dog:
    def __init__(self, name, breed):
        print(f"Creating dog: {name}, {breed}")
        self.name = name
        self.breed = breed

# Create dogs - __init__ called automatically
buddy = Dog("Buddy", "Golden Retriever")
max_dog = Dog("Max", "German Shepherd")

print(f"\nbuddyname: {buddy.name}, breed: {buddy.breed}")
print(f"max name: {max_dog.name}, breed: {max_dog.breed}")

print("\n=== Without Constructor ===")

class EmptyClass:
    pass

# Can still create but no initialization
obj = EmptyClass()
print(f"Empty object: {obj}")

# Must add attributes manually
obj.value = 42
print(f"After manual: {obj.value}")

print("\n=== Constructor vs Manual ===")

# With constructor - guaranteed state
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

p = Point(3, 4)  # Always has x and y
print(f"Point: ({p.x}, {p.y})")

# Without - inconsistent state
class BadPoint:
    pass

bp = BadPoint()
bp.x = 3
# Forgot to set y!
# print(bp.y)  # Would raise AttributeError

print("\n=== Multiple Parameters ===")

class Rectangle:
    def __init__(self, x, y, width, height):
        self.x = x
        self.y = y
        self.width = width
        self.height = height
    
    def describe(self):
        return f"Rectangle at ({self.x},{self.y}) size {self.width}x{self.height}"

rect = Rectangle(10, 20, 100, 50)
print(rect.describe())

__init__ runs when object is created. Sets up initial state.

__init__ Constructor method. Called automatically with `new Object()` in Python: `ClassName()`.

Default parameter values

Make some parameters optional.

default_values.py
# Default Values in Constructors

print("=== Default Parameter Values ===\n")

class User:
    def __init__(self, username, role="user", active=True):
        self.username = username
        self.role = role
        self.active = active
    
    def describe(self):
        status = "active" if self.active else "inactive"
        return f"{self.username} ({self.role}, {status})"

# Different ways to create
admin = User("admin", "administrator", True)  # All explicit
alice = User("alice", "editor")  # Default active
bob = User("bob")  # All defaults

print(admin.describe())
print(alice.describe())
print(bob.describe())

print("\n=== Named Arguments ===")

# Use named args to skip defaults
guest = User("guest", active=False)  # Skip role
print(guest.describe())

# Mix positional and named
mod = User("mod", role="moderator")
print(mod.describe())

print("\n=== Mutable Default Values ===")

# WRONG - Shared mutable default!
class BadList:
    def __init__(self, items=[]):
        self.items = items

bad1 = BadList()
bad2 = BadList()
bad1.items.append("item1")
print(f"bad1.items: {bad1.items}")
print(f"bad2.items: {bad2.items}")  # Also has item1!

print("\n=== Correct Pattern for Mutables ===")

# CORRECT - Use None and create new list
class GoodList:
    def __init__(self, items=None):
        self.items = items if items else []

good1 = GoodList()
good2 = GoodList()
good1.items.append("item1")
print(f"good1.items: {good1.items}")
print(f"good2.items: {good2.items}")  # Empty - correct!

print("\n=== Default with Various Types ===")

class GameCharacter:
    def __init__(self, name, health=100, inventory=None, 
                 position=None, multiplier=1.0):
        self.name = name
        self.health = health
        self.inventory = inventory if inventory else []
        self.position = position if position else {"x": 0, "y": 0}
        self.multiplier = multiplier

# Create with defaults
hero = GameCharacter("Hero")
print(f"{hero.name}: health={hero.health}, pos={hero.position}")
print(f"Inventory: {hero.inventory}")

# Create with custom values
wizard = GameCharacter("Wizard", 80, ["staff", "spellbook"], 
                       {"x": 10, "y": 5}, 1.5)
print(f"\n{wizard.name}: health={wizard.health}, pos={wizard.position}")
print(f"Inventory: {wizard.inventory}")

Parameters with defaults can be omitted: def __init__(self, name, age=0).

Validate input

Reject invalid data at creation time.

validation.py
# Input Validation in Constructors

print("=== Validation with Errors ===\n")

class Age:
    def __init__(self, years):
        if not isinstance(years, int):
            raise TypeError("Age must be an integer")
        if years < 0:
            raise ValueError("Age cannot be negative")
        if years > 150:
            raise ValueError("Age cannot exceed 150")
        self.years = years

# Valid ages
age1 = Age(25)
age2 = Age(0)
print(f"Valid ages: {age1.years}, {age2.years}")

# Invalid ages (uncomment to see errors)
# Age("twenty")  # TypeError
# Age(-5)        # ValueError
# Age(200)       # ValueError

print("\n=== Validation with Correction ===")

class Username:
    def __init__(self, name):
        # Strip whitespace
        name = name.strip()
        
        # Convert to lowercase
        name = name.lower()
        
        # Validate length
        if len(name) < 3:
            raise ValueError("Username must be at least 3 characters")
        if len(name) > 20:
            name = name[:20]  # Truncate
        
        self.name = name

user1 = Username("  Alice  ")  # Whitespace removed
user2 = Username("BOB")  # Lowercased
user3 = Username("VeryLongUsernameThatExceedsLimit")  # Truncated

print(f"'{user1.name}'")
print(f"'{user2.name}'")
print(f"'{user3.name}' (len={len(user3.name)})")

print("\n=== Validation with Defaults ===")

class Temperature:
    def __init__(self, celsius):
        # Clamp to valid range
        if celsius < -273.15:  # Absolute zero
            print(f"Warning: {celsius} adjusted to -273.15")
            celsius = -273.15
        self.celsius = celsius
    
    @property
    def fahrenheit(self):
        return self.celsius * 9/5 + 32

t1 = Temperature(25)
t2 = Temperature(-300)  # Adjusted

print(f"t1: {t1.celsius}°C")
print(f"t2: {t2.celsius}°C (was adjusted)")

print("\n=== Complex Validation ===")

class Email:
    def __init__(self, address):
        # Basic email validation
        address = address.strip().lower()
        
        if "@" not in address:
            raise ValueError("Email must contain @")
        
        parts = address.split("@")
        if len(parts) != 2:
            raise ValueError("Email must have exactly one @")
        
        local, domain = parts
        
        if not local:
            raise ValueError("Email must have local part")
        if not domain or "." not in domain:
            raise ValueError("Email must have valid domain")
        
        self.address = address
        self.local = local
        self.domain = domain

email = Email("  User@Example.COM  ")
print(f"Address: {email.address}")
print(f"Local: {email.local}, Domain: {email.domain}")

print("\n=== Validation Summary ===")

class Product:
    def __init__(self, name, price, quantity=0):
        # Name validation
        if not name or not name.strip():
            raise ValueError("Product name cannot be empty")
        self.name = name.strip()
        
        # Price validation
        if not isinstance(price, (int, float)):
            raise TypeError("Price must be a number")
        if price < 0:
            raise ValueError("Price cannot be negative")
        self.price = round(price, 2)  # Round to cents
        
        # Quantity validation
        if not isinstance(quantity, int):
            raise TypeError("Quantity must be an integer")
        if quantity < 0:
            quantity = 0  # Auto-correct
        self.quantity = quantity

laptop = Product("  Laptop  ", 999.999, 5)
print(f"Product: {laptop.name}, ${laptop.price}, qty={laptop.quantity}")

Raise exceptions in __init__ to prevent invalid objects from existing.

Computed attributes

Calculate attributes from parameters.

computed_attrs.py
# Computing Attributes in Constructor

print("=== Computed from Parameters ===\n")

class Rectangle:
    def __init__(self, width, height):
        self.width = width
        self.height = height
        # Computed attributes
        self.area = width * height
        self.perimeter = 2 * (width + height)
        self.diagonal = (width**2 + height**2) ** 0.5

rect = 
print(f"Rectangle {rect.width}x{rect.height}")
print(f"Area: {rect.area}")
print(f"Perimeter: {rect.perimeter}")
print(f"Diagonal: {rect.diagonal}")

print("\n=== Derived Attributes ===")

class Person:
    def __init__(self, first_name, last_name, birth_year):
        self.first_name = first_name
        self.last_name = last_name
        self.birth_year = birth_year
        # Derived attributes
        self.full_name = f"{first_name} {last_name}"
        self.age = 2024 - birth_year
        self.initials = f"{first_name[0]}.{last_name[0]}."

person = Person("John", "Doe", 1990)
print(f"Name: {person.full_name}")
print(f"Initials: {person.initials}")
print(f"Age: {person.age}")

print("\n=== Computed Collections ===")

class ScoreBoard:
    def __init__(self, scores):
        self.scores = list(scores)  # Copy the list
        # Compute statistics
        self.count = len(self.scores)
        self.total = sum(self.scores)
        self.average = self.total / self.count if self.count else 0
        self.highest = max(self.scores) if self.scores else None
        self.lowest = min(self.scores) if self.scores else None

board = 
print(f"Scores: {board.scores}")
print(f"Count: {board.count}, Total: {board.total}")
print(f"Average: {board.average:.1f}")
print(f"High: {board.highest}, Low: {board.lowest}")

print("\n=== Computed Flags/Status ===")

class Order:
    def __init__(self, items, discount_code=None):
        self.items = items
        self.discount_code = discount_code
        
        # Compute totals
        self.subtotal = sum(item["price"] * item["qty"] for item in items)
        
        # Apply discount
        self.discount = 0
        if discount_code == "SAVE10":
            self.discount = self.subtotal * 0.10
        elif discount_code == "SAVE20":
            self.discount = self.subtotal * 0.20
        
        self.total = self.subtotal - self.discount
        
        # Status flags
        self.is_large_order = self.total > 100
        self.has_discount = self.discount > 0
        self.item_count = sum(item["qty"] for item in items)

items = [
    {"name": "Book", "price": 15, "qty": 2},
    {"name": "Pen", "price": 5, "qty": 5}
]
order = Order(items, "SAVE10")

print(f"Items: {order.item_count}")
print(f"Subtotal: ${order.subtotal}")
print(f"Discount: ${order.discount}")
print(f"Total: ${order.total}")
print(f"Large order? {order.is_large_order}")

print("\n=== Timestamp and ID ===")

import time

class Event:
    _next_id = 1  # Class variable for ID generation
    
    def __init__(self, name, category):
        self.name = name
        self.category = category
        # Auto-generated
        self.id = Event._next_id
        Event._next_id += 1
        self.created_at = time.time()

e1 = Event("Login", "auth")
e2 = Event("Click", "ui")
e3 = Event("Purchase", "sale")

for e in [e1, e2, e3]:
    print(f"Event #{e.id}: {e.name} ({e.category})")
# Computing Attributes in Constructor

print("=== Computed from Parameters ===\n")

class Rectangle:
    def __init__(self, width, height):
        self.width = width
        self.height = height
        # Computed attributes
        self.area = width * height
        self.perimeter = 2 * (width + height)
        self.diagonal = (width**2 + height**2) ** 0.5

rect = 
print(f"Rectangle {rect.width}x{rect.height}")
print(f"Area: {rect.area}")
print(f"Perimeter: {rect.perimeter}")
print(f"Diagonal: {rect.diagonal}")

print("\n=== Derived Attributes ===")

class Person:
    def __init__(self, first_name, last_name, birth_year):
        self.first_name = first_name
        self.last_name = last_name
        self.birth_year = birth_year
        # Derived attributes
        self.full_name = f"{first_name} {last_name}"
        self.age = 2024 - birth_year
        self.initials = f"{first_name[0]}.{last_name[0]}."

person = Person("John", "Doe", 1990)
print(f"Name: {person.full_name}")
print(f"Initials: {person.initials}")
print(f"Age: {person.age}")

print("\n=== Computed Collections ===")

class ScoreBoard:
    def __init__(self, scores):
        self.scores = list(scores)  # Copy the list
        # Compute statistics
        self.count = len(self.scores)
        self.total = sum(self.scores)
        self.average = self.total / self.count if self.count else 0
        self.highest = max(self.scores) if self.scores else None
        self.lowest = min(self.scores) if self.scores else None

board = 
print(f"Scores: {board.scores}")
print(f"Count: {board.count}, Total: {board.total}")
print(f"Average: {board.average:.1f}")
print(f"High: {board.highest}, Low: {board.lowest}")

print("\n=== Computed Flags/Status ===")

class Order:
    def __init__(self, items, discount_code=None):
        self.items = items
        self.discount_code = discount_code
        
        # Compute totals
        self.subtotal = sum(item["price"] * item["qty"] for item in items)
        
        # Apply discount
        self.discount = 0
        if discount_code == "SAVE10":
            self.discount = self.subtotal * 0.10
        elif discount_code == "SAVE20":
            self.discount = self.subtotal * 0.20
        
        self.total = self.subtotal - self.discount
        
        # Status flags
        self.is_large_order = self.total > 100
        self.has_discount = self.discount > 0
        self.item_count = sum(item["qty"] for item in items)

items = [
    {"name": "Book", "price": 15, "qty": 2},
    {"name": "Pen", "price": 5, "qty": 5}
]
order = Order(items, "SAVE10")

print(f"Items: {order.item_count}")
print(f"Subtotal: ${order.subtotal}")
print(f"Discount: ${order.discount}")
print(f"Total: ${order.total}")
print(f"Large order? {order.is_large_order}")

print("\n=== Timestamp and ID ===")

import time

class Event:
    _next_id = 1  # Class variable for ID generation
    
    def __init__(self, name, category):
        self.name = name
        self.category = category
        # Auto-generated
        self.id = Event._next_id
        Event._next_id += 1
        self.created_at = time.time()

e1 = Event("Login", "auth")
e2 = Event("Click", "ui")
e3 = Event("Purchase", "sale")

for e in [e1, e2, e3]:
    print(f"Event #{e.id}: {e.name} ({e.category})")
# Computing Attributes in Constructor

print("=== Computed from Parameters ===\n")

class Rectangle:
    def __init__(self, width, height):
        self.width = width
        self.height = height
        # Computed attributes
        self.area = width * height
        self.perimeter = 2 * (width + height)
        self.diagonal = (width**2 + height**2) ** 0.5

rect = 
print(f"Rectangle {rect.width}x{rect.height}")
print(f"Area: {rect.area}")
print(f"Perimeter: {rect.perimeter}")
print(f"Diagonal: {rect.diagonal}")

print("\n=== Derived Attributes ===")

class Person:
    def __init__(self, first_name, last_name, birth_year):
        self.first_name = first_name
        self.last_name = last_name
        self.birth_year = birth_year
        # Derived attributes
        self.full_name = f"{first_name} {last_name}"
        self.age = 2024 - birth_year
        self.initials = f"{first_name[0]}.{last_name[0]}."

person = Person("John", "Doe", 1990)
print(f"Name: {person.full_name}")
print(f"Initials: {person.initials}")
print(f"Age: {person.age}")

print("\n=== Computed Collections ===")

class ScoreBoard:
    def __init__(self, scores):
        self.scores = list(scores)  # Copy the list
        # Compute statistics
        self.count = len(self.scores)
        self.total = sum(self.scores)
        self.average = self.total / self.count if self.count else 0
        self.highest = max(self.scores) if self.scores else None
        self.lowest = min(self.scores) if self.scores else None

board = 
print(f"Scores: {board.scores}")
print(f"Count: {board.count}, Total: {board.total}")
print(f"Average: {board.average:.1f}")
print(f"High: {board.highest}, Low: {board.lowest}")

print("\n=== Computed Flags/Status ===")

class Order:
    def __init__(self, items, discount_code=None):
        self.items = items
        self.discount_code = discount_code
        
        # Compute totals
        self.subtotal = sum(item["price"] * item["qty"] for item in items)
        
        # Apply discount
        self.discount = 0
        if discount_code == "SAVE10":
            self.discount = self.subtotal * 0.10
        elif discount_code == "SAVE20":
            self.discount = self.subtotal * 0.20
        
        self.total = self.subtotal - self.discount
        
        # Status flags
        self.is_large_order = self.total > 100
        self.has_discount = self.discount > 0
        self.item_count = sum(item["qty"] for item in items)

items = [
    {"name": "Book", "price": 15, "qty": 2},
    {"name": "Pen", "price": 5, "qty": 5}
]
order = Order(items, "SAVE10")

print(f"Items: {order.item_count}")
print(f"Subtotal: ${order.subtotal}")
print(f"Discount: ${order.discount}")
print(f"Total: ${order.total}")
print(f"Large order? {order.is_large_order}")

print("\n=== Timestamp and ID ===")

import time

class Event:
    _next_id = 1  # Class variable for ID generation
    
    def __init__(self, name, category):
        self.name = name
        self.category = category
        # Auto-generated
        self.id = Event._next_id
        Event._next_id += 1
        self.created_at = time.time()

e1 = Event("Login", "auth")
e2 = Event("Click", "ui")
e3 = Event("Purchase", "sale")

for e in [e1, e2, e3]:
    print(f"Event #{e.id}: {e.name} ({e.category})")
# Computing Attributes in Constructor

print("=== Computed from Parameters ===\n")

class Rectangle:
    def __init__(self, width, height):
        self.width = width
        self.height = height
        # Computed attributes
        self.area = width * height
        self.perimeter = 2 * (width + height)
        self.diagonal = (width**2 + height**2) ** 0.5

rect = 
print(f"Rectangle {rect.width}x{rect.height}")
print(f"Area: {rect.area}")
print(f"Perimeter: {rect.perimeter}")
print(f"Diagonal: {rect.diagonal}")

print("\n=== Derived Attributes ===")

class Person:
    def __init__(self, first_name, last_name, birth_year):
        self.first_name = first_name
        self.last_name = last_name
        self.birth_year = birth_year
        # Derived attributes
        self.full_name = f"{first_name} {last_name}"
        self.age = 2024 - birth_year
        self.initials = f"{first_name[0]}.{last_name[0]}."

person = Person("John", "Doe", 1990)
print(f"Name: {person.full_name}")
print(f"Initials: {person.initials}")
print(f"Age: {person.age}")

print("\n=== Computed Collections ===")

class ScoreBoard:
    def __init__(self, scores):
        self.scores = list(scores)  # Copy the list
        # Compute statistics
        self.count = len(self.scores)
        self.total = sum(self.scores)
        self.average = self.total / self.count if self.count else 0
        self.highest = max(self.scores) if self.scores else None
        self.lowest = min(self.scores) if self.scores else None

board = 
print(f"Scores: {board.scores}")
print(f"Count: {board.count}, Total: {board.total}")
print(f"Average: {board.average:.1f}")
print(f"High: {board.highest}, Low: {board.lowest}")

print("\n=== Computed Flags/Status ===")

class Order:
    def __init__(self, items, discount_code=None):
        self.items = items
        self.discount_code = discount_code
        
        # Compute totals
        self.subtotal = sum(item["price"] * item["qty"] for item in items)
        
        # Apply discount
        self.discount = 0
        if discount_code == "SAVE10":
            self.discount = self.subtotal * 0.10
        elif discount_code == "SAVE20":
            self.discount = self.subtotal * 0.20
        
        self.total = self.subtotal - self.discount
        
        # Status flags
        self.is_large_order = self.total > 100
        self.has_discount = self.discount > 0
        self.item_count = sum(item["qty"] for item in items)

items = [
    {"name": "Book", "price": 15, "qty": 2},
    {"name": "Pen", "price": 5, "qty": 5}
]
order = Order(items, "SAVE10")

print(f"Items: {order.item_count}")
print(f"Subtotal: ${order.subtotal}")
print(f"Discount: ${order.discount}")
print(f"Total: ${order.total}")
print(f"Large order? {order.is_large_order}")

print("\n=== Timestamp and ID ===")

import time

class Event:
    _next_id = 1  # Class variable for ID generation
    
    def __init__(self, name, category):
        self.name = name
        self.category = category
        # Auto-generated
        self.id = Event._next_id
        Event._next_id += 1
        self.created_at = time.time()

e1 = Event("Login", "auth")
e2 = Event("Click", "ui")
e3 = Event("Purchase", "sale")

for e in [e1, e2, e3]:
    print(f"Event #{e.id}: {e.name} ({e.category})")
# Computing Attributes in Constructor

print("=== Computed from Parameters ===\n")

class Rectangle:
    def __init__(self, width, height):
        self.width = width
        self.height = height
        # Computed attributes
        self.area = width * height
        self.perimeter = 2 * (width + height)
        self.diagonal = (width**2 + height**2) ** 0.5

rect = 
print(f"Rectangle {rect.width}x{rect.height}")
print(f"Area: {rect.area}")
print(f"Perimeter: {rect.perimeter}")
print(f"Diagonal: {rect.diagonal}")

print("\n=== Derived Attributes ===")

class Person:
    def __init__(self, first_name, last_name, birth_year):
        self.first_name = first_name
        self.last_name = last_name
        self.birth_year = birth_year
        # Derived attributes
        self.full_name = f"{first_name} {last_name}"
        self.age = 2024 - birth_year
        self.initials = f"{first_name[0]}.{last_name[0]}."

person = Person("John", "Doe", 1990)
print(f"Name: {person.full_name}")
print(f"Initials: {person.initials}")
print(f"Age: {person.age}")

print("\n=== Computed Collections ===")

class ScoreBoard:
    def __init__(self, scores):
        self.scores = list(scores)  # Copy the list
        # Compute statistics
        self.count = len(self.scores)
        self.total = sum(self.scores)
        self.average = self.total / self.count if self.count else 0
        self.highest = max(self.scores) if self.scores else None
        self.lowest = min(self.scores) if self.scores else None

board = 
print(f"Scores: {board.scores}")
print(f"Count: {board.count}, Total: {board.total}")
print(f"Average: {board.average:.1f}")
print(f"High: {board.highest}, Low: {board.lowest}")

print("\n=== Computed Flags/Status ===")

class Order:
    def __init__(self, items, discount_code=None):
        self.items = items
        self.discount_code = discount_code
        
        # Compute totals
        self.subtotal = sum(item["price"] * item["qty"] for item in items)
        
        # Apply discount
        self.discount = 0
        if discount_code == "SAVE10":
            self.discount = self.subtotal * 0.10
        elif discount_code == "SAVE20":
            self.discount = self.subtotal * 0.20
        
        self.total = self.subtotal - self.discount
        
        # Status flags
        self.is_large_order = self.total > 100
        self.has_discount = self.discount > 0
        self.item_count = sum(item["qty"] for item in items)

items = [
    {"name": "Book", "price": 15, "qty": 2},
    {"name": "Pen", "price": 5, "qty": 5}
]
order = Order(items, "SAVE10")

print(f"Items: {order.item_count}")
print(f"Subtotal: ${order.subtotal}")
print(f"Discount: ${order.discount}")
print(f"Total: ${order.total}")
print(f"Large order? {order.is_large_order}")

print("\n=== Timestamp and ID ===")

import time

class Event:
    _next_id = 1  # Class variable for ID generation
    
    def __init__(self, name, category):
        self.name = name
        self.category = category
        # Auto-generated
        self.id = Event._next_id
        Event._next_id += 1
        self.created_at = time.time()

e1 = Event("Login", "auth")
e2 = Event("Click", "ui")
e3 = Event("Purchase", "sale")

for e in [e1, e2, e3]:
    print(f"Event #{e.id}: {e.name} ({e.category})")
# Computing Attributes in Constructor

print("=== Computed from Parameters ===\n")

class Rectangle:
    def __init__(self, width, height):
        self.width = width
        self.height = height
        # Computed attributes
        self.area = width * height
        self.perimeter = 2 * (width + height)
        self.diagonal = (width**2 + height**2) ** 0.5

rect = 
print(f"Rectangle {rect.width}x{rect.height}")
print(f"Area: {rect.area}")
print(f"Perimeter: {rect.perimeter}")
print(f"Diagonal: {rect.diagonal}")

print("\n=== Derived Attributes ===")

class Person:
    def __init__(self, first_name, last_name, birth_year):
        self.first_name = first_name
        self.last_name = last_name
        self.birth_year = birth_year
        # Derived attributes
        self.full_name = f"{first_name} {last_name}"
        self.age = 2024 - birth_year
        self.initials = f"{first_name[0]}.{last_name[0]}."

person = Person("John", "Doe", 1990)
print(f"Name: {person.full_name}")
print(f"Initials: {person.initials}")
print(f"Age: {person.age}")

print("\n=== Computed Collections ===")

class ScoreBoard:
    def __init__(self, scores):
        self.scores = list(scores)  # Copy the list
        # Compute statistics
        self.count = len(self.scores)
        self.total = sum(self.scores)
        self.average = self.total / self.count if self.count else 0
        self.highest = max(self.scores) if self.scores else None
        self.lowest = min(self.scores) if self.scores else None

board = 
print(f"Scores: {board.scores}")
print(f"Count: {board.count}, Total: {board.total}")
print(f"Average: {board.average:.1f}")
print(f"High: {board.highest}, Low: {board.lowest}")

print("\n=== Computed Flags/Status ===")

class Order:
    def __init__(self, items, discount_code=None):
        self.items = items
        self.discount_code = discount_code
        
        # Compute totals
        self.subtotal = sum(item["price"] * item["qty"] for item in items)
        
        # Apply discount
        self.discount = 0
        if discount_code == "SAVE10":
            self.discount = self.subtotal * 0.10
        elif discount_code == "SAVE20":
            self.discount = self.subtotal * 0.20
        
        self.total = self.subtotal - self.discount
        
        # Status flags
        self.is_large_order = self.total > 100
        self.has_discount = self.discount > 0
        self.item_count = sum(item["qty"] for item in items)

items = [
    {"name": "Book", "price": 15, "qty": 2},
    {"name": "Pen", "price": 5, "qty": 5}
]
order = Order(items, "SAVE10")

print(f"Items: {order.item_count}")
print(f"Subtotal: ${order.subtotal}")
print(f"Discount: ${order.discount}")
print(f"Total: ${order.total}")
print(f"Large order? {order.is_large_order}")

print("\n=== Timestamp and ID ===")

import time

class Event:
    _next_id = 1  # Class variable for ID generation
    
    def __init__(self, name, category):
        self.name = name
        self.category = category
        # Auto-generated
        self.id = Event._next_id
        Event._next_id += 1
        self.created_at = time.time()

e1 = Event("Login", "auth")
e2 = Event("Click", "ui")
e3 = Event("Purchase", "sale")

for e in [e1, e2, e3]:
    print(f"Event #{e.id}: {e.name} ({e.category})")
# Computing Attributes in Constructor

print("=== Computed from Parameters ===\n")

class Rectangle:
    def __init__(self, width, height):
        self.width = width
        self.height = height
        # Computed attributes
        self.area = width * height
        self.perimeter = 2 * (width + height)
        self.diagonal = (width**2 + height**2) ** 0.5

rect = 
print(f"Rectangle {rect.width}x{rect.height}")
print(f"Area: {rect.area}")
print(f"Perimeter: {rect.perimeter}")
print(f"Diagonal: {rect.diagonal}")

print("\n=== Derived Attributes ===")

class Person:
    def __init__(self, first_name, last_name, birth_year):
        self.first_name = first_name
        self.last_name = last_name
        self.birth_year = birth_year
        # Derived attributes
        self.full_name = f"{first_name} {last_name}"
        self.age = 2024 - birth_year
        self.initials = f"{first_name[0]}.{last_name[0]}."

person = Person("John", "Doe", 1990)
print(f"Name: {person.full_name}")
print(f"Initials: {person.initials}")
print(f"Age: {person.age}")

print("\n=== Computed Collections ===")

class ScoreBoard:
    def __init__(self, scores):
        self.scores = list(scores)  # Copy the list
        # Compute statistics
        self.count = len(self.scores)
        self.total = sum(self.scores)
        self.average = self.total / self.count if self.count else 0
        self.highest = max(self.scores) if self.scores else None
        self.lowest = min(self.scores) if self.scores else None

board = 
print(f"Scores: {board.scores}")
print(f"Count: {board.count}, Total: {board.total}")
print(f"Average: {board.average:.1f}")
print(f"High: {board.highest}, Low: {board.lowest}")

print("\n=== Computed Flags/Status ===")

class Order:
    def __init__(self, items, discount_code=None):
        self.items = items
        self.discount_code = discount_code
        
        # Compute totals
        self.subtotal = sum(item["price"] * item["qty"] for item in items)
        
        # Apply discount
        self.discount = 0
        if discount_code == "SAVE10":
            self.discount = self.subtotal * 0.10
        elif discount_code == "SAVE20":
            self.discount = self.subtotal * 0.20
        
        self.total = self.subtotal - self.discount
        
        # Status flags
        self.is_large_order = self.total > 100
        self.has_discount = self.discount > 0
        self.item_count = sum(item["qty"] for item in items)

items = [
    {"name": "Book", "price": 15, "qty": 2},
    {"name": "Pen", "price": 5, "qty": 5}
]
order = Order(items, "SAVE10")

print(f"Items: {order.item_count}")
print(f"Subtotal: ${order.subtotal}")
print(f"Discount: ${order.discount}")
print(f"Total: ${order.total}")
print(f"Large order? {order.is_large_order}")

print("\n=== Timestamp and ID ===")

import time

class Event:
    _next_id = 1  # Class variable for ID generation
    
    def __init__(self, name, category):
        self.name = name
        self.category = category
        # Auto-generated
        self.id = Event._next_id
        Event._next_id += 1
        self.created_at = time.time()

e1 = Event("Login", "auth")
e2 = Event("Click", "ui")
e3 = Event("Purchase", "sale")

for e in [e1, e2, e3]:
    print(f"Event #{e.id}: {e.name} ({e.category})")
# Computing Attributes in Constructor

print("=== Computed from Parameters ===\n")

class Rectangle:
    def __init__(self, width, height):
        self.width = width
        self.height = height
        # Computed attributes
        self.area = width * height
        self.perimeter = 2 * (width + height)
        self.diagonal = (width**2 + height**2) ** 0.5

rect = 
print(f"Rectangle {rect.width}x{rect.height}")
print(f"Area: {rect.area}")
print(f"Perimeter: {rect.perimeter}")
print(f"Diagonal: {rect.diagonal}")

print("\n=== Derived Attributes ===")

class Person:
    def __init__(self, first_name, last_name, birth_year):
        self.first_name = first_name
        self.last_name = last_name
        self.birth_year = birth_year
        # Derived attributes
        self.full_name = f"{first_name} {last_name}"
        self.age = 2024 - birth_year
        self.initials = f"{first_name[0]}.{last_name[0]}."

person = Person("John", "Doe", 1990)
print(f"Name: {person.full_name}")
print(f"Initials: {person.initials}")
print(f"Age: {person.age}")

print("\n=== Computed Collections ===")

class ScoreBoard:
    def __init__(self, scores):
        self.scores = list(scores)  # Copy the list
        # Compute statistics
        self.count = len(self.scores)
        self.total = sum(self.scores)
        self.average = self.total / self.count if self.count else 0
        self.highest = max(self.scores) if self.scores else None
        self.lowest = min(self.scores) if self.scores else None

board = 
print(f"Scores: {board.scores}")
print(f"Count: {board.count}, Total: {board.total}")
print(f"Average: {board.average:.1f}")
print(f"High: {board.highest}, Low: {board.lowest}")

print("\n=== Computed Flags/Status ===")

class Order:
    def __init__(self, items, discount_code=None):
        self.items = items
        self.discount_code = discount_code
        
        # Compute totals
        self.subtotal = sum(item["price"] * item["qty"] for item in items)
        
        # Apply discount
        self.discount = 0
        if discount_code == "SAVE10":
            self.discount = self.subtotal * 0.10
        elif discount_code == "SAVE20":
            self.discount = self.subtotal * 0.20
        
        self.total = self.subtotal - self.discount
        
        # Status flags
        self.is_large_order = self.total > 100
        self.has_discount = self.discount > 0
        self.item_count = sum(item["qty"] for item in items)

items = [
    {"name": "Book", "price": 15, "qty": 2},
    {"name": "Pen", "price": 5, "qty": 5}
]
order = Order(items, "SAVE10")

print(f"Items: {order.item_count}")
print(f"Subtotal: ${order.subtotal}")
print(f"Discount: ${order.discount}")
print(f"Total: ${order.total}")
print(f"Large order? {order.is_large_order}")

print("\n=== Timestamp and ID ===")

import time

class Event:
    _next_id = 1  # Class variable for ID generation
    
    def __init__(self, name, category):
        self.name = name
        self.category = category
        # Auto-generated
        self.id = Event._next_id
        Event._next_id += 1
        self.created_at = time.time()

e1 = Event("Login", "auth")
e2 = Event("Click", "ui")
e3 = Event("Purchase", "sale")

for e in [e1, e2, e3]:
    print(f"Event #{e.id}: {e.name} ({e.category})")
# Computing Attributes in Constructor

print("=== Computed from Parameters ===\n")

class Rectangle:
    def __init__(self, width, height):
        self.width = width
        self.height = height
        # Computed attributes
        self.area = width * height
        self.perimeter = 2 * (width + height)
        self.diagonal = (width**2 + height**2) ** 0.5

rect = 
print(f"Rectangle {rect.width}x{rect.height}")
print(f"Area: {rect.area}")
print(f"Perimeter: {rect.perimeter}")
print(f"Diagonal: {rect.diagonal}")

print("\n=== Derived Attributes ===")

class Person:
    def __init__(self, first_name, last_name, birth_year):
        self.first_name = first_name
        self.last_name = last_name
        self.birth_year = birth_year
        # Derived attributes
        self.full_name = f"{first_name} {last_name}"
        self.age = 2024 - birth_year
        self.initials = f"{first_name[0]}.{last_name[0]}."

person = Person("John", "Doe", 1990)
print(f"Name: {person.full_name}")
print(f"Initials: {person.initials}")
print(f"Age: {person.age}")

print("\n=== Computed Collections ===")

class ScoreBoard:
    def __init__(self, scores):
        self.scores = list(scores)  # Copy the list
        # Compute statistics
        self.count = len(self.scores)
        self.total = sum(self.scores)
        self.average = self.total / self.count if self.count else 0
        self.highest = max(self.scores) if self.scores else None
        self.lowest = min(self.scores) if self.scores else None

board = 
print(f"Scores: {board.scores}")
print(f"Count: {board.count}, Total: {board.total}")
print(f"Average: {board.average:.1f}")
print(f"High: {board.highest}, Low: {board.lowest}")

print("\n=== Computed Flags/Status ===")

class Order:
    def __init__(self, items, discount_code=None):
        self.items = items
        self.discount_code = discount_code
        
        # Compute totals
        self.subtotal = sum(item["price"] * item["qty"] for item in items)
        
        # Apply discount
        self.discount = 0
        if discount_code == "SAVE10":
            self.discount = self.subtotal * 0.10
        elif discount_code == "SAVE20":
            self.discount = self.subtotal * 0.20
        
        self.total = self.subtotal - self.discount
        
        # Status flags
        self.is_large_order = self.total > 100
        self.has_discount = self.discount > 0
        self.item_count = sum(item["qty"] for item in items)

items = [
    {"name": "Book", "price": 15, "qty": 2},
    {"name": "Pen", "price": 5, "qty": 5}
]
order = Order(items, "SAVE10")

print(f"Items: {order.item_count}")
print(f"Subtotal: ${order.subtotal}")
print(f"Discount: ${order.discount}")
print(f"Total: ${order.total}")
print(f"Large order? {order.is_large_order}")

print("\n=== Timestamp and ID ===")

import time

class Event:
    _next_id = 1  # Class variable for ID generation
    
    def __init__(self, name, category):
        self.name = name
        self.category = category
        # Auto-generated
        self.id = Event._next_id
        Event._next_id += 1
        self.created_at = time.time()

e1 = Event("Login", "auth")
e2 = Event("Click", "ui")
e3 = Event("Purchase", "sale")

for e in [e1, e2, e3]:
    print(f"Event #{e.id}: {e.name} ({e.category})")

Store computed values: self.area = width * height.

Common initialization patterns

Flexible constructors with various parameter styles.

init_patterns.py
# Common Initialization Patterns

print("=== Factory-Style Constructor ===\n")

class Color:
    def __init__(self, r, g, b):
        self.r = r
        self.g = g
        self.b = b
    
    @classmethod
    def from_hex(cls, hex_code):
        """Create Color from hex string like '#FF0000'"""
        hex_code = hex_code.lstrip('#')
        r = int(hex_code[0:2], 16)
        g = int(hex_code[2:4], 16)
        b = int(hex_code[4:6], 16)
        return cls(r, g, b)
    
    @classmethod
    def from_name(cls, name):
        colors = {
            "red": (255, 0, 0),
            "green": (0, 255, 0),
            "blue": (0, 0, 255),
            "white": (255, 255, 255),
            "black": (0, 0, 0)
        }
        rgb = colors.get(name.lower(), (0, 0, 0))
        return cls(*rgb)
    
    def __str__(self):
        return f"RGB({self.r}, {self.g}, {self.b})"

# Multiple ways to create
c1 = Color(255, 128, 0)  # Direct
c2 = Color.from_hex("#00FF00")  # From hex
c3 = Color.from_name("blue")  # From name

print(f"Direct: {c1}")
print(f"From hex: {c2}")
print(f"From name: {c3}")

print("\n=== Configuration Object ===")

class Config:
    def __init__(self, **kwargs):
        # Set defaults
        self.debug = False
        self.log_level = "INFO"
        self.max_connections = 100
        self.timeout = 30
        
        # Override with provided values
        for key, value in kwargs.items():
            if hasattr(self, key):
                setattr(self, key, value)
            else:
                print(f"Warning: Unknown config '{key}'")
    
    def display(self):
        print(f"  debug: {self.debug}")
        print(f"  log_level: {self.log_level}")
        print(f"  max_connections: {self.max_connections}")
        print(f"  timeout: {self.timeout}")

# Default config
cfg1 = Config()
print("Default config:")
cfg1.display()

# Custom config
cfg2 = Config(debug=True, timeout=60, unknown="ignored")
print("\nCustom config:")
cfg2.display()

print("\n=== Copy Constructor Pattern ===")

class Point:
    def __init__(self, x=0, y=0):
        self.x = x
        self.y = y
    
    def copy(self):
        """Create a copy of this point"""
        return Point(self.x, self.y)
    
    @classmethod
    def from_point(cls, other):
        """Create from another Point"""
        return cls(other.x, other.y)
    
    def __repr__(self):
        return f"Point({self.x}, {self.y})"

p1 = Point(10, 20)
p2 = p1.copy()  # Using instance method
p3 = Point.from_point(p1)  # Using classmethod

p2.x = 100  # Change copy
print(f"Original: {p1}")
print(f"Copy (changed): {p2}")
print(f"From point: {p3}")

print("\n=== Dependent Initialization ===")

class Database:
    def __init__(self, host, port, database):
        self.host = host
        self.port = port
        self.database = database
        # Build connection string
        self.connection_string = f"db://{host}:{port}/{database}"
        # Initialize state
        self.connected = False
        self.queries_run = 0
    
    def connect(self):
        print(f"Connecting to {self.connection_string}...")
        self.connected = True
    
    def query(self, sql):
        if not self.connected:
            raise RuntimeError("Not connected")
        self.queries_run += 1
        print(f"Running query #{self.queries_run}: {sql}")

db = Database("localhost", 5432, "myapp")
print(f"Connection string: {db.connection_string}")
db.connect()
db.query("SELECT * FROM users")

Use *args, **kwargs, or factory methods for flexible initialization.

Exercise: practical.py

Build a class with validation and computed attributes