Skip to content

Latest commit

 

History

History
291 lines (209 loc) · 7.76 KB

README.md

File metadata and controls

291 lines (209 loc) · 7.76 KB

Chapter 7: Object-Oriented Programming

Table of Contents

OOP and Class Concepts

Object-Oriented Programming (OOP) is a programming paradigm that uses objects and classes to structure code. A class is a blueprint for creating objects, and an object is an instance of a class.

Defining a Class

A class is defined using the class keyword, followed by the class name and a colon. The class contains methods (functions) and attributes (variables).

class Car:
    def __init__(self, brand, model, year, color):
        self.brand = brand
        self.model = model
        self.year = year
        self.color = color

    def drive(self):
        print(f"{self.brand} {self.model} is driving...")

    def stop(self):
        print(f"{self.brand} {self.model} is stopping...")

car1 = Car("BMW", "X5", 2021, "Black")
car2 = Car("Ford", "Mustang", 2022, "Blue")

car1.drive()
car2.drive()
car1.stop()

Output:

BMW X5 is driving...
Ford Mustang is driving...
BMW X5 is stopping...

Explanation: The Car class has an __init__ method that initializes the attributes of the class. The drive and stop methods define the behavior of the class. We create two instances of the Car class and call their methods.

Attributes and Methods

Attributes are variables that belong to a class, and methods are functions that belong to a class.

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def greet(self):
        print(f"Hello, my name is {self.name} and I am {self.age} years old.")

person1 = Person("Alice", 30)
person1.greet()

Output:

Hello, my name is Alice and I am 30 years old.

Explanation: The Person class has two attributes, name and age, and one method, greet. The greet method prints a greeting message using the attributes.

Dunder (Magic) Methods

Dunder (Double UNDERscore) methods, also known as magic methods, are special methods in Python that start and end with double underscores. They allow you to define the behavior of objects for built-in operations.

Example: Dunder Methods

class Character:
    def __init__(self, name):
        self.name = name
        self.health = 100
        self.arr = ['A', 'B', 'C']

    def is_died(self):
        return self.health == 0

    def damage(self, value):
        self.health = max(0, self.health - value)

    def __str__(self):
        return f"{self.name} with {self.health}HP"

    def __len__(self):
        return self.health

    def __getitem__(self, item):
        return self.arr[item]

    def __eq__(self, other):
        return self.health == other.health

    def __lt__(self, other):
        return self.health < other.health

    def __add__(self, other):
        return self.health + other.health

alpha = Character(name="Alpha")
beta = Character(name="Beta")

print(len(alpha))
print(alpha)
print(alpha[1])
print(alpha == beta)
alpha.damage(75)
print(alpha < beta)
print(alpha + beta)

Output:

100
Alpha with 100HP
B
True
True
125

Explanation: The Character class defines several dunder methods to customize its behavior. The __str__ method defines the string representation of the object, the __len__ method returns the length (health) of the object, and the __getitem__ method allows indexing. The __eq__, __lt__, and __add__ methods define equality, less than, and addition operations, respectively.

Inheritance

Inheritance allows a class to inherit attributes and methods from another class. The class that inherits is called the child class, and the class being inherited from is called the parent class.

Example: Inheritance

class Person:
    def __init__(self, full_name, age):
        self.full_name = full_name
        self.age = age

    def greet(self):
        print(f"Hello!")

    def show_info(self):
        print("Full Name:", self.full_name)
        print("Age:", self.age)

class Student(Person):
    def __init__(self, full_name, age, grade):
        super().__init__(name, age)
        self.grade = grade

    def say_grade(self):
        super().greet()
        print(f"{self.full_name}'s grade is {self.grade}")

    def show_info(self):
        super().show_info()
        print("Grade:", self.grade)

student1 = Student('John Doe', 13, 7)
person1 = Person("Nazim Ramazanli", 30)

student1.say_grade()
student1.show_info()
person1.show_info()

Output:

Hello!
John Doe's grade is 7
Full Name: John Doe
Age: 13
Grade: 7
Full Name: Nazim Ramazanli
Age: 30

Explanation: The Student class inherits from the Person class. It uses the super() function to call the parent class's methods and attributes. The Student class adds a new attribute grade and overrides the show_info method.

@staticmethod

The @staticmethod decorator defines a static method that does not require an instance of the class to be called. Static methods do not have access to the instance (self) or class (cls) variables.

Example: @staticmethod

class Calculator:
    @staticmethod
    def add(x, y):
        return x + y

    @staticmethod
    def subtract(x, y):
        return x - y

print(Calculator.add(3, 4))
print(Calculator.subtract(10, 5))

Output:

7
5

Explanation: The Calculator class defines two static methods, add and subtract, using the @staticmethod decorator. These methods can be called directly on the class without creating an instance.

@classmethod

The @classmethod decorator defines a class method that takes the class itself as the first argument (cls). Class methods can access and modify class-level variables.

Example: @classmethod

class Student:
    student_count = 0
    instances = []

    def __init__(self, name, score):
        self.name = name
        self.score = score
        Student.student_count += 1
        Student.instances.append(self)

    @classmethod
    def get_student_count(cls):
        return f"Student count: {cls.student_count}"

    @classmethod
    def convert(cls, students):
        result = []
        for student in students:
            result.append(cls(student["name"], student["score"]))
        return result

bob = Student('Bob', 93)
alice = Student('Alice', 89)
mark = Student('Mark', 75)

print(Student.get_student_count())

data = [
    {"name": "Nihad", "score": 95},
    {"name": "Akif", "score": 83},
    {"name": "Nilay", "score": 94},
]

converted_data = Student.convert(data)
print(*[f"{instance.name}'s score is {instance.score}" for instance in converted_data], sep='\n')

Output:

Student count: 3
Nihad's score is 95
Akif's score is 83
Nilay's score is 94

Explanation: The Student class defines two class methods, get_student_count and convert, using the @classmethod decorator. The get_student_count method returns the number of student instances, and the convert method converts a list of dictionaries into a list of Student instances.

Summary

In this chapter, we covered Object-Oriented Programming concepts, including defining classes, dunder (magic) methods, inheritance, static methods, and class methods.

Tasks

  1. Define a class Animal with attributes name and species, and methods speak and info.
  2. Create a subclass Dog that inherits from Animal and adds a new method bark.
  3. Define a class MathOperations with static methods for addition, subtraction, multiplication, and division.
  4. Define a class Employee with class methods to keep track of the number of employees and convert a list of dictionaries into a list of Employee instances.

Next Chapter: Advanced Topics