Session 4: Object Model & Class FundamentalsΒΆ
Week: 4
Element: ICTPRG430 Element 2.1
Duration: 4 hours
Phase: Object-Oriented Programming Theory
π Lecture SlidesΒΆ
Week 4 Presentation Slides
View the interactive presentation slides for this session:
π Open Slides in New Window pptx slides
The slides cover:
- Why OOP works (encapsulation, modularity, reusability)
- Classes vs objects β blueprints and instances
- UML class diagrams for BankAccount
- Encapsulation with @property and @setter
- Magic methods __str__ and __repr__
- Single Responsibility Principle
- 7-step BankAccount implementation walkthrough
Session IntroductionΒΆ
In this session you will explore the foundational concepts of Object-Oriented Programming (OOP) through universal examples. You'll understand why OOP is essential for managing complexity, then apply those patterns to design and implement a RobotBase class in your assessment. This session emphasizes learning patterns through clear, relatable examples that you'll then apply independently.
Learning ObjectivesΒΆ
By the end of this session, you will be able to:
- Understand fundamental OOP concepts: classes, objects, and object instantiation
- Design a class with appropriate instance variables and methods
- Explain encapsulation principles and their benefit for software design
- Write getter and setter methods to safely access and modify object state
- Use Python decorators (
@property,@setter) to enforce method-based access - Implement magic methods (
__str__,__repr__) for object representation - Apply single responsibility principle to class design
- Apply learned patterns to implement a RobotBase class from a specification
Session StructureΒΆ
- Why OOP Works - Managing complexity, encapsulation, modularity, reusability
- Classes and Objects - Blueprints and instances
- Encapsulation Patterns - Safely access and modify instance variables
- @property and @setter Decorators - Python's elegant way to enforce methods
- Magic Methods - String representation (str, repr)
- Single Responsibility Principle - One method, one job
- 7-Step Implementation - Complete working class with all concepts
- Assessment - Apply patterns to RobotBase (separate, spec-based)
Pre-Session PreparationΒΆ
Required
- Python 3.9+ installed
- VS Code with Python extension
- Basic familiarity with functions and data types
Review
- Function definitions and parameters
- Python dictionaries and lists
- Basic testing concepts (from Sessions 1-3)
1. Why Object-Oriented Programming?ΒΆ
Software systems are complex with multiple components that must work together. OOP provides the structure needed to manage this complexity.
Key AdvantagesΒΆ
Encapsulation: Hide complexity behind clear interfaces - Example: Bank balance doesn't expose internal transaction log - Benefit: Change internal implementation without breaking client code
Modularity: Each component is independent - Example: Balance calculation, transaction methods, status reporting - Benefit: Test and update each component in isolation
Reusability: Design once, use everywhere - Example: Same patterns work for bank accounts, student records, inventory, robots - Benefit: Universal design patterns apply everywhere
Flexibility: Change behavior without touching other components - Example: Change how interest is calculated - Benefit: Updates don't break rest of system
2. Classes and Objects: The FoundationΒΆ
Understanding the RelationshipΒΆ
Class: A blueprint or template for creating objects
- Like architectural plans for a building
- Defines structure (instance variables) and capabilities (methods)
- PascalCase naming: BankAccount, Student, Robot
Object (Instance): An individual "thing" created from a class
- Like actual buildings constructed from plans
- Each has unique state and identity
- Multiple objects can come from one class: account1, account2, account3
Python Class BasicsΒΆ
A Python class defines a blueprint. Here's the essential pattern:
class BankAccount:
"""Blueprint for bank account objects."""
def __init__(self, holder_name, account_type, balance):
"""Initialize instance variables (state)."""
self.holder_name = holder_name
self.account_type = account_type
self.balance = balance
def deposit(self, amount):
"""Method - what the object can do."""
self.balance += amount
3. The Key: Understanding selfΒΆ
self is the reference to the specific object. It's how Python knows which object's data to modify.
# Create two separate objects
alice_account = BankAccount("Alice", "Savings", 1000)
bob_account = BankAccount("Bob", "Checking", 500)
# Each has independent state
alice_account.deposit(100) # Changes alice_account's balance
bob_account.deposit(50) # Changes bob_account's balance
# They don't affect each other
print(alice_account.balance) # 1100
print(bob_account.balance) # 550
Inside the deposit method:
- When called on alice_account, self refers to alice_account
- When called on bob_account, self refers to bob_account
- Python automatically passes the correct object as self
4. Encapsulation: Protecting Your DataΒΆ
The Problem: Direct AccessΒΆ
Without encapsulation, anyone can modify state however they want:
account = BankAccount("Alice", "Savings", 1000)
account.balance = -1000000 # Oops! No validation!
account.balance = "rich" # Type error!
The Solution: Private VariablesΒΆ
Use underscore prefix to signal "don't access directly":
class BankAccount:
def __init__(self, holder_name, account_type, balance):
self._holder_name = holder_name # Private!
self._account_type = account_type
self._balance = balance
Then provide controlled access through methods:
def get_balance(self):
"""Getter - read access only."""
return self._balance
def set_balance(self, value):
"""Setter - write access with validation."""
if value < 0:
raise ValueError("Balance cannot be negative")
self._balance = value
5. Python's Elegant Solution: @propertyΒΆ
Instead of get_ and set_ methods, Python uses decorators:
class BankAccount:
def __init__(self, holder_name, account_type, balance):
self._balance = balance
@property
def balance(self):
"""Getter - called when you read the attribute."""
return self._balance
@balance.setter
def balance(self, value):
"""Setter - called when you assign the attribute."""
if value < 0:
raise ValueError("Balance cannot be negative")
self._balance = value
# Usage - looks like an attribute, but validated!
account = BankAccount("Alice", "Savings", 1000)
print(account.balance) # Calls @property getter
account.balance = 500 # Calls @setter with validation
account.balance = -100 # ValueError! Protected!
Why @property is BetterΒΆ
- Cleaner syntax: Looks like
account.balance, notaccount.get_balance() - Protected: Validation happens automatically
- Flexible: Can change from attribute to method later without breaking client code
6. Magic Methods: String RepresentationΒΆ
Magic methods (double underscore methods) are called automatically by Python.
__str__() - User-Friendly StringΒΆ
Called by print() and str(). Should be simple and readable:
def __str__(self):
"""Return string for print()."""
return f"BankAccount({self._holder_name}, ${self._balance:.2f})"
# Usage
account = BankAccount("Alice", "Savings", 1500)
print(account) # Calls __str__()
# Output: BankAccount(Alice, $1500.00)
__repr__() - Developer-Friendly StringΒΆ
Called in interactive mode and for debugging. Should be detailed and unambiguous:
def __repr__(self):
"""Return string for developers."""
return (f"BankAccount(holder_name='{self._holder_name}', "
f"account_type='{self._account_type}', "
f"balance={self._balance})")
# Usage in Python REPL
account = BankAccount("Alice", "Savings", 1500)
account # Calls __repr__()
# Output: BankAccount(holder_name='Alice', account_type='Savings', balance=1500)
7. Single Responsibility PrincipleΒΆ
Each method should do ONE thing clearly.
Good ExampleΒΆ
class BankAccount:
def deposit(self, amount):
"""Do ONE thing: add money to account."""
self._balance += amount
def withdraw(self, amount):
"""Do ONE thing: remove money from account."""
if amount > self._balance:
raise ValueError("Insufficient funds")
self._balance -= amount
def calculate_interest(self):
"""Do ONE thing: calculate and apply interest."""
interest = self._balance * (self._interest_rate / 100)
self._balance += interest
return interest
BenefitsΒΆ
- Easy to test (each method has one behavior)
- Easy to maintain (change one responsibility at a time)
- Easy to reuse (clear purpose)
- Easy to understand (no side effects)
8. Implementation Pattern: 7 StepsΒΆ
The Session 4 slides show a complete 7-step implementation pattern using BankAccount:
- Class Definition &
__init__- Initialize all instance variables - @property Decorators - Provide read-only access
- @setter Decorators - Controlled write access with validation
- Regular Methods - Operations on the object
- Calculation Methods - Complex operations
- Status Methods - Report object state
- Magic Methods -
__str__()and__repr__()
See the slides for complete, working code examples of each step.
9. Your Assessment: RobotBaseΒΆ
You will apply these OOP patterns to implement a RobotBase class for robotics control.
What You GetΒΆ
- Specification document - What RobotBase must do
- Unit tests - Automated feedback on correctness
- Starter template - Method signatures to fill in
- Competency checklist - Self-verification
What You Don't GetΒΆ
- No complete code examples for RobotBase
- No working implementation to copy
- No step-by-step implementation guide
Why This MattersΒΆ
Seeing the BankAccount pattern teaches you OOP. Building RobotBase independently proves you understand it.
10. Key Concepts SummaryΒΆ
| Concept | What It Is | Why It Matters |
|---|---|---|
| Class | Blueprint for objects | Defines structure and behavior |
| Object | Instance of a class | Each has independent state |
| self | Reference to current object | Python knows which object to modify |
| Private variables | _name with underscore |
Signals "internal only" |
| @property | Decorator for getter | Clean read-only access |
| @setter | Decorator for validation | Protected write access |
| Magic methods | __str__, __repr__ |
Called automatically by Python |
| Single Responsibility | One method, one job | Easier to test, maintain, understand |
11. Resource LinksΒΆ
- Session 4 Slides - Full BankAccount implementation (study this!)
- Assessment Specification - RobotBase requirements
- Unit Tests - What your code must pass
- Competency Checklist - Self-verify your understanding
SummaryΒΆ
In Session 4 you will:
- Learn OOP patterns via BankAccount examples
- Understand why encapsulation, validation, and magic methods matter
- See a complete 7-step implementation pattern
- Apply these patterns to RobotBase in your assessment
The assessment tests whether you can apply patterns, not whether you can copy code. Study the BankAccount examples, understand the patterns, then implement RobotBase independently.
Ready? Check out the slides and let's code! π
Session 4 Assessment: RobotBase ClassΒΆ
OverviewΒΆ
Between Session 4 and Session 5, you will implement a RobotBase class from a UML diagram. This assessment tests whether you can apply the OOP patterns you learned with BankAccount to a different domain (robotics).
Key Point: You've seen the full BankAccount implementation. RobotBase is specification-only β you must understand patterns to implement it independently.
What You'll BuildΒΆ
A RobotBase class matching this UML design:
βββββββββββββββββββββββββββββββββββββββββββββββββββ
β RobotBase β
βββββββββββββββββββββββββββββββββββββββββββββββββββ€
β - _name : str β
β - _battery_level : float β
β - _is_moving : bool β
β - _sensor_readings : dict β
βββββββββββββββββββββββββββββββββββββββββββββββββββ€
β + name : str Β«read-only propertyΒ» β
β + battery_level : float Β«read/write propertyΒ» β
β + is_moving : bool Β«read-only propertyΒ» β
β + sensor_readings : dict Β«read-only propertyΒ» β
βββββββββββββββββββββββββββββββββββββββββββββββββββ€
β + move_forward(speed: int) : None β
β + stop() : None β
β + get_sensor_reading(name: str) : float β
β + set_sensor_reading(name: str, value: float) β
β + report_status() : str β
β + __str__() : str β
β + __repr__() : str β
βββββββββββββββββββββββββββββββββββββββββββββββββββ
How to Approach ItΒΆ
- Study the UML Diagram β Understand the class structure above
- Study the BankAccount Examples β How patterns were applied to banking
- Connect the Patterns β See how BankAccount patterns apply to RobotBase
- Implement Independently β Write your own code, don't copy
- Submit β Save as
solution.pyand submit by [due date]
Key Patterns to ApplyΒΆ
From BankAccount, transfer these patterns to RobotBase:
| Pattern | BankAccount Example | RobotBase Application |
|---|---|---|
| Private Variables | self._balance |
self._battery_level, self._is_moving |
| @property Getter | balance property (read-only) |
battery_level property (read-only) |
| @setter Validation | balance.setter checks >= 0 |
battery_level.setter checks 0-100 |
| Action Methods | deposit(), withdraw() |
move_forward(), stop() |
| Sensor Access | get_balance() method |
get_sensor_reading(), set_sensor_reading() |
| str | User-friendly output | Robot status display |
| repr | Developer-friendly output | Full state for debugging |
| Single Responsibility | One method = one job | Each method has one purpose |
What You Can UseΒΆ
β Study These: - Session 4 slides (BankAccount implementation) - BankAccount code examples in content - UML diagram above (class structure)
β Don't Do This: - Copy code from slides (it's BankAccount, not RobotBase) - Look for RobotBase code anywhere (there isn't any) - Copy from classmates - Use external libraries (only Python standard library)
GradingΒΆ
This is competency-based. Your implementation is assessed on:
- β Code follows OOP patterns correctly
- β Validation enforced (battery constraints, movement logic)
- β
Magic methods implemented (
__str__,__repr__) - β Private variables and properties used correctly
- β Methods have single responsibility
Your code either demonstrates the competency or it needs revision.
Getting HelpΒΆ
If stuck: 1. Review the UML diagram β Does your class structure match? 2. Compare to BankAccount β How was this pattern implemented there? 3. Ask in office hours β But don't ask for code, ask about patterns
Assessment Timeline: - Session 4 (today): Learn patterns, review UML, start implementation - Between sessions: Complete implementation - Session 5: Submit solution, discuss patterns