0%

35- Introduction to Object

Objects bundle data and behavior together. Classes are blueprints. OOP is not just a programming style. It is a way of thinking about code as real-world things.

You have written functions. You have used data structures. Your code works. But as programs grow, they become harder to manage. Functions are scattered. Data floats around. Keeping everything connected becomes a challenge. Object-Oriented Programming (OOP) offers a different approach. Instead of separating data and functions, you bundle them together into objects. An object contains both the data (attributes) and the functions that operate on that data (methods). Think of a car. A car has data: color, speed, fuel level. A car has behaviors: accelerate, brake, refuel. In procedural programming, you would have separate variables for color, speed, and separate functions that take those variables as parameters. In OOP, the car is an object that contains its own data and methods. This lesson introduces the core concepts of OOP: classes, objects, attributes, methods, and the four pillars: encapsulation, inheritance, polymorphism, and abstraction.

🕯️ Magic Note

Python is object-oriented from the ground up. Everything in Python is an object. Every string, every list, every function, every module. When you call “hello”.upper(), you are using OOP. You have been using OOP throughout this entire course. Now you will learn how to create your own objects.

What is a Class?
A class is a blueprint or template for creating objects. It defines what attributes and methods an object will have. You can think of a class as a cookie cutter. Objects are the cookies.

Python

# Defining a simple class

class Dog:

pass # Empty class (just a placeholder)

# Creating objects from the class

buddy = Dog()

max = Dog()

print(type(buddy)) # <class ‘__main__.Dog’>

print(type(max)) # <class ‘__main__.Dog’>

print(buddy is max) # False (different objects)

What is an Object?
An object is an instance of a class. It is a concrete thing created from the blueprint. Each object has its own copy of the class’s attributes.

Python

# String is a class. “hello” and “world” are objects (instances)

text1 = “hello”

text2 = “world”

print(type(text1)) # <class ‘str’>

print(type(text2)) # <class ‘str’>

# List is a class. [1,2,3] is an object

numbers = [1, 2, 3]

print(type(numbers)) # <class ‘list’>

🕯️ Magic Note

The terms “class” and “type” are often used interchangeably in Python. class Dog: creates a new type. Instances of that type are objects.

The __init__ Method (Constructor)
The __init__ method (pronounced “dunder init” or “magic init”) is called automatically when you create an object. It initializes the object’s attributes.

Python

class Dog:

def __init__(self, name, age):

self.name = name # Attribute: name

self.age = age # Attribute: age

# Creating objects (__init__ is called automatically)

buddy = Dog(“Buddy”, 3)

max = Dog(“Max”, 5)

print(buddy.name) # Buddy

print(buddy.age) # 3

print(max.name) # Max

print(max.age) # 5

💡 The first parameter of any instance method (including __init__) is always self. It refers to the current object. By convention, it is called self. You could name it anything, but always use self. It is a Python convention followed by all programmers.
Instance Methods
Instance methods are functions defined inside a class that operate on instances of that class. They always take self as the first parameter.

Python

class Dog:

def __init__(self, name, age):

self.name = name

self.age = age

self.energy = 100

def bark(self):

print(f”{self.name} says: Woof!”)

def run(self, distance):

self.energy -= distance

print(f”{self.name} ran {distance} meters. Energy is now {self.energy}”)

def sleep(self):

self.energy = 100

print(f”{self.name} slept and regained full energy!”)

# Using methods

buddy = Dog(“Buddy”, 3)

buddy.bark() # Buddy says: Woof!

buddy.run(30) # Buddy ran 30 meters. Energy is now 70

buddy.sleep() # Buddy slept and regained full energy!

🕯️ Magic Note

When you call buddy.bark(), Python automatically passes the object buddy as the self parameter. This is why methods can access the object’s attributes.

Instance Attributes vs Class Attributes
Instance attributes belong to individual objects. Class attributes are shared by all instances of the class.

Python

class Dog:

# Class attribute (shared by all dogs)

species = “Canis familiaris”

def __init__(self, name, age):

# Instance attributes (unique to each dog)

self.name = name

self.age = age

buddy = Dog(“Buddy”, 3)

max = Dog(“Max”, 5)

# Both dogs share the same class attribute

print(buddy.species) # Canis familiaris

print(max.species) # Canis familiaris

# Access via the class itself

print(Dog.species) # Canis familiaris

# Changing class attribute changes it for all instances

Dog.species = “Canis lupus familiaris”

print(buddy.species) # Canis lupus familiaris

print(max.species) # Canis lupus familiaris

⚠️ Be careful with mutable class attributes. If you modify a list or dictionary that is a class attribute, the change affects all instances. This is often not what you want.

Python

class Student:

# Dangerous: mutable class attribute

courses = [] # Shared by all students!

def __init__(self, name):

self.name = name

def add_course(self, course):

self.courses.append(course) # Modifies the class attribute!

ali = Student(“Ali”)

sara = Student(“Sara”)

ali.add_course(“Python”)

sara.add_course(“JavaScript”)

print(ali.courses) # [‘Python’, ‘JavaScript’] (not what Ali expects)

print(sara.courses) # [‘Python’, ‘JavaScript’] (not what Sara expects)

# Correct approach: use instance attribute

class StudentCorrect:

def __init__(self, name):

self.name = name

self.courses = [] # Each student gets their own list

def add_course(self, course):

self.courses.append(course)

The Four Pillars of OOP
Object-Oriented Programming is built on four core concepts. You will learn each in detail in the coming lessons.
PillarMeaningBenefit
EncapsulationBundling data and methods together. Hiding internal details.Protects data integrity, reduces complexity
InheritanceCreating new classes based on existing ones. Reusing code.Eliminates redundancy, establishes relationships
PolymorphismSame interface, different implementations. One name, many forms.Flexibility, extensibility
AbstractionHiding complex implementation details. Showing only essentials.Simplifies usage, reduces cognitive load

Python

# Example overview of the four pillars (simplified)

# (Each will be covered in full detail later)

# Encapsulation: data and methods together

class BankAccount:

def __init__(self, balance):

self._balance = balance # Internal attribute (convention)

def deposit(self, amount):

self._balance += amount # Controlled access

# Inheritance: reusing code

class SavingsAccount(BankAccount): # Inherits from BankAccount

def add_interest(self):

self._balance *= 1.05

# Polymorphism: same method name, different behavior

class Cat:

def sound(self):

return “Meow”

class Dog:

def sound(self):

return “Woof”

animals = [Cat(), Dog()]

for animal in animals:

print(animal.sound()) # Same call, different results

# Abstraction: hiding complexity

class CoffeeMachine:

def make_coffee(self):

self._heat_water()

self._grind_beans()

self._brew()

# User only needs to call make_coffee()

def _heat_water(self): pass # Internal method (convention)

def _grind_beans(self): pass

def _brew(self): pass

Why Use OOP?
OOP is not always the right answer, but it is powerful for many problems.
  • Organizes code around real-world entities and relationships
  • Reuses code through inheritance (DRY principle)
  • Protects data through encapsulation
  • Makes code more modular and maintainable
  • Easier to model complex systems with interacting parts
A Complete Example: A Simple Bank Account
Here is a complete class demonstrating core OOP concepts in action.

Python

class BankAccount:

# Class attribute (shared by all accounts)

bank_name = “Feloriya National Bank”

def __init__(self, owner, initial_balance=0):

# Instance attributes

self.owner = owner

self._balance = initial_balance # Internal attribute (underscore convention)

self._transaction_history = []

def deposit(self, amount):

if amount <= 0:

raise ValueError(“Deposit amount must be positive”)

self._balance += amount

self._transaction_history.append(f”+{amount}”)

print(f”Deposited {amount}. New balance: {self._balance}”)

def withdraw(self, amount):

if amount <= 0:

raise ValueError(“Withdrawal amount must be positive”)

if amount > self._balance:

raise ValueError(“Insufficient funds”)

self._balance -= amount

self._transaction_history.append(f”-{amount}”)

print(f”Withdrew {amount}. New balance: {self._balance}”)

def get_balance(self):

# Getter method (encapsulation)

return self._balance

def get_history(self):

return self._transaction_history.copy() # Return a copy to prevent modification

def __str__(self):

# Magic method called by str() and print()

return f”Account(owner={self.owner}, balance={self._balance})”

# Using the class

account = BankAccount(“Feloriya”, 1000)

account.deposit(500)

account.withdraw(200)

print(f”Final balance: {account.get_balance()}”)

print(account) # Uses __str__ method

print(BankAccount.bank_name) # Access class attribute

Common OOP Mistakes for Beginners
  • Forgetting the self parameter in method definitions
  • Forgetting to use self when accessing attributes inside methods
  • Using mutable class attributes when you meant instance attributes
  • Creating classes that are too big (doing too many things)
  • Using classes when a simple function or dictionary would suffice
  • Not using __init__ to initialize attributes
Check Your Understanding
  • What is the difference between a class and an object?
  • What does the __init__ method do?
  • What is the purpose of the self parameter?
  • What is the difference between a class attribute and an instance attribute?
  • Name the four pillars of OOP.
  • Write a simple Car class with attributes make, model, and year, and a method display_info().

⚡ Whisper

OOP is a way of seeing the world. You look at your problem and you ask: what are the things here? A bank has accounts. A game has players and enemies. A store has products and customers. Each thing has data (color, size, price) and behaviors (buy, sell, move, attack). You bundle them together. You call them objects. This is not magic. It is just a different way to organize your thoughts. Sometimes OOP is perfect. Sometimes it is overkill. The art is knowing when. But learning OOP changes how you think about code. You start seeing patterns. You start reusing structures. You start building systems that mirror the real world. This lesson is the door. The next lessons will take you through the rooms. Walk slowly. Try every example. Build your own classes. The object-oriented path is wide. Many have walked it before you. Now it is your turn.

Related posts