Skip to main content

Phase 01: Foundations of Python and Mathematics

Day 04: Object-Oriented Programming

πŸ“‘ Table of Contents

  1. 🌟 Welcome to Day 4
  2. πŸ—οΈ Object Oriented Programming Basics
    • Classes and Objects
    • Attributes and Methods
    • Inheritance
    • Encapsulation
    • Polymorphism
    • Special Methods
  3. πŸ“¦ Modules in Python
    • Importing Modules
    • Creating Your Own Modules
    • Using Built-in Modules
  4. πŸ“ Packages in Python
    • Understanding Packages
    • Creating and Importing Packages
  5. πŸ’» Hands-On Coding
    • Example Scripts
  6. 🧩 Interactive Exercises
  7. πŸ“š Resources
  8. πŸ’‘ 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:

  1. Create a directory named my_package.
  2. Inside my_package, create an __init__.py file (can be empty).
  3. 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 attributes name, age, and grade. 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 attributes name and salary. Create a subclass Manager that inherits from Employee and adds an attribute department. 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 and Cat with a method speak. Implement a function that takes an animal object and calls its speak 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:


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
  • 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!")
    
TensorFlow-Developers/TensorFlow_90_Day_Guide/Phase1_Foundations_of_Python_and_Mathematics/Day4_Object_Oriented_Programming at main Β· ahammadmejbah/TensorFlow-Developers
Welcome to the TensorFlow 90-Day Guide, your comprehensive roadmap to mastering TensorFlow and Neural Networks in just three months! This guide is meticulously structured to take you from a beginne…