Day 04: Object-Oriented Programming
π Table of Contents
- π Welcome to Day 4
- ποΈ Object Oriented Programming Basics
- Classes and Objects
- Attributes and Methods
- Inheritance
- Encapsulation
- Polymorphism
- Special Methods
- π¦ Modules in Python
- Importing Modules
- Creating Your Own Modules
- Using Built-in Modules
- π Packages in Python
- Understanding Packages
- Creating and Importing Packages
- π» Hands-On Coding
- Example Scripts
- 𧩠Interactive Exercises
- π Resources
- π‘ Tips and Tricks
1. π Welcome to Day 4
Welcome to Day 4 of "Becoming a Scikit-Learn Boss in 90 Days"! π Today, we dive deep into Object Oriented Programming (OOP) in Python, a paradigm that allows for more organized and efficient code management. OOP is fundamental in building scalable and maintainable machine learning projects. Let's explore the core concepts of OOP and how to implement them in Python! π
2. ποΈ Object Oriented Programming Basics
OOP is a programming paradigm based on the concept of "objects", which can contain data and code to manipulate that data. The main principles of OOP are:
π Classes and Objects
-
Class: A blueprint for creating objects. It defines a set of attributes and methods that the created objects will have.
-
Object: An instance of a class. It represents an entity with state and behavior.
Example:
class Dog:
def __init__(self, name, age):
self.name = name # Attribute
self.age = age # Attribute
def bark(self):
print(f"{self.name} says woof!")
# Creating objects
dog1 = Dog("Buddy", 3)
dog2 = Dog("Lucy", 5)
# Using methods
dog1.bark() # Output: Buddy says woof!
dog2.bark() # Output: Lucy says woof!
π Attributes and Methods
-
Attributes: Variables that hold data related to the object.
-
Methods: Functions defined within a class that describe the behaviors of the object.
Example:
class Car:
# Class attribute
wheels = 4
def __init__(self, make, model):
self.make = make # Instance attribute
self.model = model # Instance attribute
def drive(self):
print(f"The {self.make} {self.model} is driving.")
# Creating an object
car = Car("Toyota", "Corolla")
print(car.wheels) # Output: 4
car.drive() # Output: The Toyota Corolla is driving.
π Inheritance
Inheritance allows a class (child class) to inherit attributes and methods from another class (parent class). This promotes code reuse and establishes a relationship between classes.
Example:
class Animal:
def __init__(self, name):
self.name = name
def speak(self):
pass # To be overridden by subclasses
class Dog(Animal):
def speak(self):
print(f"{self.name} says woof!")
class Cat(Animal):
def speak(self):
print(f"{self.name} says meow!")
# Creating objects
dog = Dog("Buddy")
cat = Cat("Whiskers")
dog.speak() # Output: Buddy says woof!
cat.speak() # Output: Whiskers says meow!
π Encapsulation
Encapsulation is the bundling of data (attributes) and methods that operate on the data within a single unit (class). It also involves restricting access to some of the object's components, which is a means of preventing accidental interference and misuse.
Example:
class BankAccount:
def __init__(self, owner, balance=0):
self.owner = owner
self.__balance = balance # Private attribute
def deposit(self, amount):
if amount > 0:
self.__balance += amount
print(f"Deposited {amount}. New balance: {self.__balance}")
else:
print("Deposit amount must be positive.")
def withdraw(self, amount):
if 0 < amount <= self.__balance:
self.__balance -= amount
print(f"Withdrew {amount}. New balance: {self.__balance}")
else:
print("Insufficient balance or invalid amount.")
def get_balance(self):
return self.__balance
# Creating an object
account = BankAccount("Alice")
# Accessing public attributes and methods
print(account.owner) # Output: Alice
account.deposit(500) # Output: Deposited 500. New balance: 500
account.withdraw(200) # Output: Withdrew 200. New balance: 300
print(account.get_balance()) # Output: 300
# Trying to access private attribute (will raise AttributeError)
# print(account.__balance)
π Polymorphism
Polymorphism allows objects of different classes to be treated as objects of a common superclass. It enables the same interface to be used for different underlying forms (data types).
Example:
class Bird:
def fly(self):
print("Flying in the sky.")
class Airplane:
def fly(self):
print("Flying with engines.")
def make_it_fly(flyable):
flyable.fly()
# Creating objects
bird = Bird()
plane = Airplane()
# Using polymorphism
make_it_fly(bird) # Output: Flying in the sky.
make_it_fly(plane) # Output: Flying with engines.
π Special Methods
Special methods (also known as magic methods) are predefined methods in Python classes that start and end with double underscores __
. They allow classes to implement and customize behavior for built-in operations.
Example:
class Vector:
def __init__(self, x, y):
self.x = x
self.y = y
# String representation
def __str__(self):
return f"Vector({self.x}, {self.y})"
# Addition
def __add__(self, other):
return Vector(self.x + other.x, self.y + other.y)
# Representation for debugging
def __repr__(self):
return self.__str__()
# Creating objects
v1 = Vector(2, 3)
v2 = Vector(4, 5)
# Using special methods
print(v1) # Output: Vector(2, 3)
print(v2) # Output: Vector(4, 5)
print(v1 + v2) # Output: Vector(6, 8)
3. π¦ Modules in Python
Modules are Python files containing functions, classes, or variables that you can include in your projects. They help in organizing code into manageable and reusable components.
π Importing Modules
You can import entire modules or specific functions/classes from a module.
Example:
import math
print(math.sqrt(16)) # Output: 4.0
Importing Specific Functions:
from math import pi, sin
print(pi) # Output: 3.141592653589793
print(sin(pi / 2)) # Output: 1.0
π Creating Your Own Modules
To create your own module, simply save a Python file (e.g., math_utils.py
) with function definitions.
math_utils.py:
def multiply(a, b):
return a * b
def divide(a, b):
if b == 0:
return "Cannot divide by zero!"
return a / b
Using math_utils.py:
import math_utils
print(math_utils.multiply(4, 5)) # Output: 20
print(math_utils.divide(10, 2)) # Output: 5.0
print(math_utils.divide(10, 0)) # Output: Cannot divide by zero!
π Using Built-in Modules
Python comes with a rich set of built-in modules that you can use without installing anything.
Example:
import datetime
current_time = datetime.datetime.now()
print(current_time)
4. π Packages in Python
Packages are collections of modules organized in directories. They help in structuring large codebases and avoiding module name conflicts.
π Understanding Packages
A package is a directory containing an __init__.py
file and multiple modules.
Directory Structure:
my_package/
__init__.py
module1.py
module2.py
π Creating and Importing Packages
Creating a Package:
- Create a directory named
my_package
. - Inside
my_package
, create an__init__.py
file (can be empty). - Add your modules (
module1.py
,module2.py
, etc.).
Using the Package:
from my_package import module1, module2
module1.function_a()
module2.function_b()
Example:
my_package/module1.py:
def function_a():
print("Function A from Module 1")
my_package/module2.py:
def function_b():
print("Function B from Module 2")
main.py:
from my_package import module1, module2
module1.function_a() # Output: Function A from Module 1
module2.function_b() # Output: Function B from Module 2
5. π» Hands-On Coding
π Example Scripts
π Script 1: Managing a Library System
# library.py
class Book:
def __init__(self, title, author, copies=1):
self.title = title
self.author = author
self.copies = copies
def add_copies(self, number):
self.copies += number
print(f"Added {number} copies of '{self.title}'. Total copies: {self.copies}")
def remove_copies(self, number):
if number <= self.copies:
self.copies -= number
print(f"Removed {number} copies of '{self.title}'. Total copies: {self.copies}")
else:
print("Not enough copies to remove.")
class Library:
def __init__(self):
self.books = {}
def add_book(self, book):
if book.title in self.books:
self.books[book.title].add_copies(book.copies)
else:
self.books[book.title] = book
print(f"Added '{book.title}' to the library.")
def remove_book(self, title, copies=1):
if title in self.books:
self.books[title].remove_copies(copies)
if self.books[title].copies == 0:
del self.books[title]
print(f"'{title}' has been removed from the library.")
else:
print(f"Book '{title}' not found in the library.")
def display_books(self):
if not self.books:
print("No books in the library.")
return
for title, book in self.books.items():
print(f"Title: {book.title}, Author: {book.author}, Copies: {book.copies}")
def main():
library = Library()
# Adding books
book1 = Book("1984", "George Orwell", 3)
book2 = Book("To Kill a Mockingbird", "Harper Lee", 2)
library.add_book(book1)
library.add_book(book2)
# Display books
library.display_books()
# Adding more copies
book3 = Book("1984", "George Orwell", 2)
library.add_book(book3)
# Display books
library.display_books()
# Removing copies
library.remove_book("1984", 4)
# Display books
library.display_books()
# Removing all copies
library.remove_book("To Kill a Mockingbird", 2)
# Display books
library.display_books()
if __name__ == "__main__":
main()
π Script 2: Using Inheritance
# shapes.py
class Shape:
def __init__(self, name):
self.name = name
def area(self):
pass
def perimeter(self):
pass
class Rectangle(Shape):
def __init__(self, width, height):
super().__init__("Rectangle")
self.width = width
self.height = height
def area(self):
return self.width * self.height
def perimeter(self):
return 2 * (self.width + self.height)
class Circle(Shape):
def __init__(self, radius):
super().__init__("Circle")
self.radius = radius
def area(self):
import math
return math.pi * self.radius ** 2
def perimeter(self):
import math
return 2 * math.pi * self.radius
def main():
shapes = [
Rectangle(3, 4),
Circle(5)
]
for shape in shapes:
print(f"{shape.name} - Area: {shape.area()}, Perimeter: {shape.perimeter()}")
if __name__ == "__main__":
main()
π Script 3: Polymorphism with Different Shapes
# polymorphism_example.py
class Shape:
def area(self):
pass
class Square(Shape):
def __init__(self, side):
self.side = side
def area(self):
return self.side ** 2
class Triangle(Shape):
def __init__(self, base, height):
self.base = base
self.height = height
def area(self):
return 0.5 * self.base * self.height
def display_area(shape):
print(f"Area: {shape.area()}")
def main():
square = Square(4)
triangle = Triangle(3, 6)
display_area(square) # Output: Area: 16
display_area(triangle) # Output: Area: 9.0
if __name__ == "__main__":
main()
π Script 4: Creating and Using Packages
math_operations.py
# math_operations.py
def add(a, b):
return a + b
def subtract(a, b):
return a - b
def multiply(a, b):
return a * b
def divide(a, b):
if b == 0:
return "Cannot divide by zero!"
return a / b
main.py
# main.py
import math_operations
def main():
print(math_operations.add(10, 5)) # Output: 15
print(math_operations.subtract(10, 5)) # Output: 5
print(math_operations.multiply(10, 5)) # Output: 50
print(math_operations.divide(10, 5)) # Output: 2.0
print(math_operations.divide(10, 0)) # Output: Cannot divide by zero!
if __name__ == "__main__":
main()
6. 𧩠Interactive Exercises
π Exercise 1: Creating a Class
-
Task: Create a class
Student
with attributesname
,age
, andgrade
. Include methods to update the grade and display student information.class Student: def __init__(self, name, age, grade): self.name = name self.age = age self.grade = grade def update_grade(self, new_grade): self.grade = new_grade print(f"{self.name}'s grade updated to {self.grade}") def display_info(self): print(f"Name: {self.name}, Age: {self.age}, Grade: {self.grade}") # Example usage student = Student("John Doe", 20, "A") student.display_info() # Output: Name: John Doe, Age: 20, Grade: A student.update_grade("A+") # Output: John Doe's grade updated to A+ student.display_info() # Output: Name: John Doe, Age: 20, Grade: A+
π Exercise 2: Inheritance
-
Task: Create a base class
Employee
with attributesname
andsalary
. Create a subclassManager
that inherits fromEmployee
and adds an attributedepartment
. Include methods to display employee information.class Employee: def __init__(self, name, salary): self.name = name self.salary = salary def display_info(self): print(f"Name: {self.name}, Salary: {self.salary}") class Manager(Employee): def __init__(self, name, salary, department): super().__init__(name, salary) self.department = department def display_info(self): super().display_info() print(f"Department: {self.department}") # Example usage emp = Employee("Alice", 70000) emp.display_info() # Output: Name: Alice, Salary: 70000 mgr = Manager("Bob", 90000, "HR") mgr.display_info() # Output: # Name: Bob, Salary: 90000 # Department: HR
π Exercise 3: Encapsulation
-
Task: Create a class
BankAccount
with a private attribute__balance
. Implement methods to deposit, withdraw, and check balance without directly accessing the__balance
.class BankAccount: def __init__(self, owner, balance=0): self.owner = owner self.__balance = balance def deposit(self, amount): if amount > 0: self.__balance += amount print(f"Deposited {amount}. New balance: {self.__balance}") else: print("Deposit amount must be positive.") def withdraw(self, amount): if 0 < amount <= self.__balance: self.__balance -= amount print(f"Withdrew {amount}. New balance: {self.__balance}") else: print("Insufficient balance or invalid amount.") def get_balance(self): return self.__balance # Example usage account = BankAccount("Charlie") account.deposit(500) # Output: Deposited 500. New balance: 500 account.withdraw(200) # Output: Withdrew 200. New balance: 300 print(account.get_balance()) # Output: 300
π Exercise 4: Polymorphism
-
Task: Create classes
Dog
andCat
with a methodspeak
. Implement a function that takes an animal object and calls itsspeak
method.class Dog: def speak(self): print("Woof!") class Cat: def speak(self): print("Meow!") def make_animal_speak(animal): animal.speak() # Example usage dog = Dog() cat = Cat() make_animal_speak(dog) # Output: Woof! make_animal_speak(cat) # Output: Meow!
π Exercise 5: Special Methods
-
Task: Create a class
Point
that represents a point in 2D space. Implement the__str__
and__add__
special methods to allow string representation and addition of two points.class Point: def __init__(self, x, y): self.x = x self.y = y def __str__(self): return f"Point({self.x}, {self.y})" def __add__(self, other): return Point(self.x + other.x, self.y + other.y) # Example usage p1 = Point(2, 3) p2 = Point(4, 5) print(p1) # Output: Point(2, 3) print(p2) # Output: Point(4, 5) p3 = p1 + p2 print(p3) # Output: Point(6, 8)
7. π Resources
Enhance your learning with these excellent resources:
- Official Python Documentation
- W3Schools Python Tutorial
- Real Python
- Python for Everybody (Coursera)
- Automate the Boring Stuff with Python
- Codecademy Python Course
- LeetCode Python Problems
8. π‘ Tips and Tricks
π‘ Pro Tip
Virtual Environments: Always use virtual environments to manage your project dependencies. This keeps your projects isolated and prevents version conflicts.
# Create a virtual environment
python3 -m venv my_env
# Activate the virtual environment
source my_env/bin/activate # On Windows: my_env\Scripts\activate
# Install packages
pip install package_name
π οΈ Recommended Tools
- Visual Studio Code: A powerful code editor with Python extensions.
- PyCharm: An IDE specifically designed for Python development.
- Jupyter Notebook: Interactive notebooks for data analysis and visualization.
π Speed Up Your Coding
- Use List Comprehensions: They provide a concise way to create lists.
squares = [x**2 for x in range(10)]
- Leverage Built-in Functions: Python's standard library offers a plethora of useful functions.
numbers = [1, 2, 3, 4, 5] print(sum(numbers)) # Output: 15 print(max(numbers)) # Output: 5
π Debugging Tips
- Use Print Statements: Simple yet effective for tracking variable values.
- Leverage Debuggers: Tools like the built-in debugger in VS Code can help step through your code.
- Handle Exceptions: Gracefully handle errors to prevent your program from crashing.
try: result = 10 / 0 except ZeroDivisionError: print("Cannot divide by zero!")