โณ Loading Python Engine...

๐Ÿ“Š Day 16 : OOP Basics

๐ŸŽฏ Enterprise Objective

As programs grow, functional code can become messy spaghetti. Object-Oriented Programming (OOP) allows us to encapsulate state and behavior into clean, reusable models. Today we master the syntax of Classes, the init constructor, and the DRY (Don't Repeat Yourself) principle of Inheritance.

๐Ÿ“‹ Strategic Overview

#TopicConcept
1ClassesBlueprints for objects
2Constructorinit and self
3InheritanceReusing logic with super()

1. Classes & Objects : Modeling the World

๐Ÿ” What is it?

Object-Oriented Programming (OOP) groups data (attributes) and behavior (methods) into a single template called a Class. When you create a specific instance of that class, it is called an Object.

class User:
    pass

alice = User() # Create an object (instance)

๐Ÿ’ผ Why Data Analysts Care

โ€ข Code Organization: Bundling messy API connection variables and functions into a clean APIClient class

โ€ข Data Modeling: Creating a DataRow class that knows how to clean its own data

โš ๏ธ Over-engineering

Don't use OOP if a simple dictionary and a function will do the job. Python supports both functional and OOP paradigms. Use OOP when you need to manage complex state.

In [ ]:

๐Ÿงช Concept Checks: Classes

Q1. Define a class Car. Create two instances, car1 and car2.

In [ ]:

Q2. Assign a color attribute to car1 (e.g., "Red"). Print it.

In [ ]:

Q3. Try to access the color attribute on car2. Catch the AttributeError.

In [ ]:

Q4. Print the type() of car1. What does it say?

In [ ]:

Q5. Explain the difference between a Class and an Object using a real-world analogy.

In [ ]:

2. __init__ and self : The Constructor

๐Ÿ” What is it?

To set up an object properly when it is created, we use the constructor method: init. The first parameter of EVERY method must be self, which refers to the specific object being manipulated.

class User:
    def __init__(self, name, age):
        self.name = name  # Attribute assignment
        self.age = age

alice = User('Alice', 25) # __init__ is called automatically

๐Ÿ’ผ Why Data Analysts Care

โ€ข Initialization: Ensuring a database connection object immediately connects when instantiated

โ€ข State Management: Tracking variables like self.is_logged_in across different method calls

๐Ÿง  Pro Tip

Dunder methods (like init, with double underscores) are 'magic methods' that Python calls automatically behind the scenes. You rarely call them directly.

In [ ]:

๐Ÿงช Concept Checks: Init & Self

Q1. Create a Book class with an init that takes title and author.

In [ ]:

Q2. Create an instance of Book and print its title.

In [ ]:

Q3. Add a method summary(self) to Book that prints "[title] by [author]". Call it.

In [ ]:

Q4. Add a default argument is_read=False to the init. Prove it works by creating a book and checking the attribute.

In [ ]:

Q5. Why is self required as the first argument in instance methods? What happens if you forget it?

In [ ]:

3. Inheritance : Reusing Class Logic

๐Ÿ” What is it?
Inheritance allows a new Class (Child) to adopt the attributes and methods of an existing Class (Parent). This promotes code reuse. You use super() to call methods from the Parent class.
class Employee:
    def work(self): print('Working')

class Manager(Employee): # Inherits from Employee
    def meeting(self): print('In a meeting')

๐Ÿ’ผ Why Data Analysts Care

โ€ข Code Reuse: Creating CSVReader and JSONReader that both inherit from a base DataReader class

โ€ข Specialization: Creating specific exception types that inherit from Exception

โš ๏ธ Deep Hierarchies

Avoid creating deeply nested inheritance chains (A inherits B inherits C inherits D). It makes code impossible to debug. Prefer 'Composition' over deep Inheritance.

In [ ]:

๐Ÿงช Concept Checks: Inheritance

Q1. Create a parent class Vehicle with init(self, speed). Add a move method.

In [ ]:

Q2. Create a child class Bicycle(Vehicle). Call its move method to prove it inherited it.

In [ ]:

Q3. Override the move method in Bicycle to print "Pedaling at [speed]". Call it.

In [ ]:

Q4. Create a child class Car(Vehicle). Use super().init(speed) to add a new brand attribute.

In [ ]:

Q5. Check if Car is a subclass of Vehicle using issubclass(Car, Vehicle). Print the result.

In [ ]:

๐Ÿ› ๏ธ Professional Practice Tasks

Theory is useless without muscle memory. Complete these tasks to solidify your understanding.

Task 1 (Bank Account): Create a BankAccount class with balance (default 0). Add deposit(amt) and withdraw(amt) methods. Prevent overdrafts (withdrawals > balance). Test it.

In [ ]:

Task 2 (Data Analyzer): Create a Dataset class initialized with a list of numbers. Add methods mean(), max(), and min(). Instantiate and test.

In [ ]:

Task 3 (Shape Inheritance): Create Shape class with area() -> 0. Create Rectangle(Shape) and Circle(Shape) that override area() with actual math. Create one of each and print areas.

In [ ]:

Task 4 (Employee Roster): Create an Employee class (name, salary). Create Manager(Employee) that adds an add_report() method to track a list of employees. Add 2 employees to a manager.

In [ ]:

Task 5 (API Client Mock): Create an APIClient class with base_url. Add a method get(endpoint) that prints Fetching [base_url]/[endpoint]. Test it.

In [ ]:

๐Ÿ’ป Pure Coding Interview Questions

Q1.

Write a Dog class. Create 3 instances with different names. Print type() and id() for each to prove they are separate objects of the same class.

In [ ]:

Q2.

Write a Counter class where init sets self.count = 0. Add an increment method. Show that two instances have independent counters.

In [ ]:

Q3.

Write a class method that deliberately omits self. Call it on an instance, catch the TypeError, and print the error message to show why self is required.

In [ ]:

Q4.

Write a Shape base class with area() returning 0. Write Circle(Shape) overriding area() with pi r*2. Create both and print .area().

In [ ]:

Q5.

Write a Vehicle class. Create Car(Vehicle) adding a brand attribute using super().init(). Print the car's speed and brand.

In [ ]:

Q6.

Write a class with a class attribute count = 0 and increment it inside init. Create 3 objects. Print MyClass.count showing it tracks instances.

In [ ]:

Q7.

Write a class with a class attribute count that tracks instances. Add an init that increments it. Create 5 objects, delete 2, show count remains 5.

In [ ]:

Q8.

Write a parent Animal class with speak() returning '...'. Write Dog(Animal) and Cat(Animal) overriding speak(). Call .speak() on each.

In [ ]:

Q9.

Write a Dog, Cat, and Bird class each with a speak() method. Write a function animal_sounds(animals) that calls .speak() on any animal passed in.

In [ ]:

Q10.

Write code using ClassName.mro() to print the Method Resolution Order of a class with diamond inheritance (A->B, A->C, B,C->D).

In [ ]:

Q11.

Write three unrelated classes (Dog, Cat, Robot) each with a .greet() method. Write a function that calls .greet() on any object โ€” demonstrating polymorphism.

In [ ]:

Q12.

Write a JSONMixin class with to_json(self) using json.dumps(self.dict). Write User(JSONMixin) and call user.to_json().

In [ ]:

Q13.

Write a class with _salary (private by convention). Add a @property that returns it as $XX,XXX. Demonstrate accessing it both ways.

In [ ]:

Q14.

Write a class using name (name mangling). Show that obj.name raises AttributeError but obj._ClassName__name works.

In [ ]:

Q15.

Write a Rectangle class with width and height. Add @property area that returns width * height. Access it without parentheses.

In [ ]:

Q16.

Write a Date class with @classmethod from_string(cls, s) that parses '25-12-2023'. Create d = Date.from_string('25-12-2023') and print d.year.

In [ ]:

Q17.

Write a MathUtils class with @staticmethod is_prime(n) that checks primality. Call it without creating an instance.

In [ ]:

Q18.

Write a custom ValidationError(Exception) class with a field attribute. Raise it and catch it, printing the field name.

In [ ]:

Q19.

Write a ShoppingCart class that holds a list of Item(name, price) objects (composition). Add total() method. Test with 3 items.

In [ ]:

Q20.

Write a ShoppingCart class using composition: it contains a list of Item objects. Add add_item() and total() methods.

In [ ]:

Q21.

Write a class implementing str, repr, and len. Demonstrate that print(), repr(), and len() call each respectively.

In [ ]:

Q22.

Write a User(name, email) class with str returning 'name ' and repr returning 'User(name, email)'.

In [ ]:

Q23.

Write a class Bag that implements len returning the count of items stored internally. Test with len(bag).

In [ ]:

Q24.

Write a class Row that stores a dict and implements getitem(key) so you can access fields like row['name'].

In [ ]:

Q25.

Write two unrelated classes (Duck, Person) both with .quack(). Write a function that calls .quack() on whatever is passed โ€” demonstrating duck typing.

In [ ]:

๐Ÿ“Š Day 16 Executive Summary

#TopicKey Takeaway
1ClassBundles data and functions together
2SelfRefers to the specific instance being operated on
3Inheritclass Child(Parent): shares methods instantly

โœ… Instructor's End-of-Day Checklist

โ€ข [ ] I can define a Class and instantiate an Object.

โ€ข [ ] I understand self and init.

โ€ข [ ] I can inherit from a parent class.