Oop
Master classes, objects, and design principles to write structured, reusable, professional-grade code.
Part of the free Python course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
What You'll Learn in This Lesson
- • What a class is and how to create objects from it
- • Instance variables vs class variables
- • The four pillars: encapsulation, abstraction, inheritance, polymorphism
- • Writing __init__ , __str__ , and instance methods
- • When to use classes vs plain functions
1️⃣ Introduction — Why Learn OOP
Think of OOP like building with LEGO. Instead of one giant pile of bricks (procedural code), you have organized sets with instructions (classes) that you can use to build specific things (objects). You can reuse the same instructions to build multiple houses, cars, or robots!
Up to now, you've written procedural code — a series of instructions that run top-to-bottom. That works for small scripts, but large projects quickly become messy.
Object-Oriented Programming (OOP) fixes that. It organizes code around objects — bundles of data (attributes) and behavior (methods) that represent real-world concepts.
Concept
What It Means
Real-World Example
Class
A blueprint/template
A cookie cutter shape
Object
An instance of a class
An actual cookie made from the cutter
Attribute
Data/properties of an object
Cookie's flavor, size, color
Method
Actions an object can do
Cookie can be eaten, decorated
This structure powers everything from games and AI frameworks to mobile apps and APIs built in Python.
2️⃣ What Are Classes and Objects?
A class defines the blueprint or concept (like "Dog"). An object (or instance) is a specific example of that concept (like "Buddy").
💡 How to Read This: The class Dog: line creates the blueprint. The dog1 = Dog("Buddy", 3) line creates an actual dog object named Buddy who is 3 years old.
Each object has its own data (name, age) but shares the same class definition.
3️⃣ Understanding the self Parameter
self is like saying "me" or "this object". When a dog object calls bark() , self refers to THAT specific dog. It's how the object knows its own name, age, etc.
Inside a class, every method receives self as the first argument. self represents the current object, allowing access to its own data.
💡 Remember: You MUST include self as the first parameter in every method inside a class. Python passes it automatically when you call the method — you never type it yourself!
When you call cat.meow() , Python automatically passes that instance as self .
4️⃣ Class Attributes vs Instance Attributes
Class Attributes
These are shared by all objects of that class.
Change Dog.species once and it affects every dog.
Instance Attributes
5️⃣ Adding Behavior with Methods
Methods are functions inside classes that act on that object's data.
Whenever you see a design that repeats logic, wrap it inside a method — it's cleaner and reusable.
6️⃣ Constructors — __init__()
__init__() is like the "birth certificate" of an object. When a baby is born, you record their name, birth date, etc. Similarly, when an object is created, __init__() sets up all its initial information.
The special __init__() method (called a constructor) runs automatically every time you create a new object.
Part
Meaning
def __init__(self, ...):
Define the constructor method
self
The object being created
self.name = name
Save the parameter as an attribute
You can think of __init__ as the setup stage for each object.
7️⃣ Magic (Special) Methods in Python
Python classes can override built-in behavior by defining dunder (double-underscore) methods.
Method
Purpose
Example
__init__()
Constructor
Initialize attributes
__str__()
Human-friendly string
Used by print(obj)
__repr__()
Official representation
Used in debug tools
__len__()
Length behavior
Makes len(obj) work
__add__()
Add operator
obj1 + obj2
__eq__()
Equality check
obj1 == obj2
8️⃣ Encapsulation — Protecting Data
Encapsulation is like a vending machine. You can see what's available and insert money (public interface), but you can't reach inside and grab items directly (private data). The machine controls how you interact with it.
Encapsulation means keeping data safe inside a class, exposing only what's needed. You hide details using private attributes (by convention, prefix with underscore).
Convention
name
Public - accessible anywhere
self.name
_name
Protected - "please don't touch"
self._balance
__name
Private - name mangling applied
self.__secret
This approach is standard in finance, games, and apps where data integrity matters.
9️⃣ Abstraction — Simplify Complexity
Abstraction hides unnecessary details so the user focuses on what matters.
Example: You use print() without worrying about how text is sent to stdout.
All the complex steps stay hidden inside brew() .
🔟 Inheritance — Reuse Existing Code
Inheritance is like family traits. A child inherits features from parents (eye color, height), but can also have their own unique features. In code, a "child" class inherits from a "parent" class.
(Full lesson follows next module, but short preview here.)
Term
Also Called
Description
Parent Class
Base / Super class
The class being inherited FROM
Child Class
Derived / Sub class
The class that inherits
Now Dog inherits everything from Animal and customizes speak() .
11️⃣ Polymorphism — Same Name, Different Behavior
Polymorphism means "many forms". Think of the word "open" — you can open a door, open a book, open an app. Same word, different actions depending on what you're opening. In code, different objects respond to the same method call in their own way.
Different objects can share method names but act differently:
💡 Why This Matters: You can write code that works with ANY object that has a certain method, without knowing the exact type. This makes your code flexible and extensible!
12️⃣ Designing Readable Classes
Good Naming
Use nouns for class names ( Book , Student ) and verbs for methods ( calculate_total , display_info ).
Docstrings
13️⃣ Class vs Static Methods
Class methods operate on the class itself, not instances. Static methods don't use self or cls — they're utility functions inside a class.
Type
First Parameter
Use Case
Instance method
Needs object data
@classmethod
cls
Needs class data, factory methods
@staticmethod
none
Utility function, no class/object data needed
14️⃣ Practical Example — Book Class 📚
15️⃣ Practical Example — Rectangle Class 📏
16️⃣ Practical Example — Student Class 🎓
This model mirrors real-life objects — names, attributes, behaviors.
17️⃣ Practical Example — ShoppingCart 🛒
18️⃣ Advanced OOP Concepts — Deep Dive
Inheritance in Detail
Multiple Inheritance
Polymorphism in Practice
Different objects responding to the same message:
Composition — "Has a" Relationship
Instead of inheriting, you can combine objects.
19️⃣ Practical Mini-Project — Library System 📖
This project demonstrates encapsulation, composition, and real-world thinking in code design.
20️⃣ When to Use OOP
- Your program models real-world entities (users, products, orders).
- Code needs to be reused or extended.
- You're building systems with multiple components (games, apps, APIs).
If your code is short and one-off, functions may be enough. But for any project you plan to grow, OOP keeps it organized and maintainable.
21️⃣ Best Practices ✅
- ✔ Each class should have a single responsibility.
- ✔ Keep methods small and focused.
- ✔ Use meaningful names.
- ✔ Hide internal data with underscores.
- ✔ Favor composition over deep inheritance.
- ✔ Add docstrings for clarity.
- ✔ Test classes individually.
These habits match professional guidelines (PEP 8 and SOLID principles).
22️⃣ Common Errors and Fixes 🧯
Error
Cause
Solution
TypeError: missing 1 required positional argument
Forgot self in method definition
Add self as first parameter
AttributeError
Accessing nonexistent attribute
Check name and constructor
NameError
Used variable before defining
Initialize inside __init__()
Circular import
Two modules import each other
Restructure code into packages
Remember that Python module names are case-sensitive on most systems.
🎯 23️⃣ Mini Challenges
- Book Class: title, author, pages, and __str__.
- Rectangle: methods for area & perimeter.
- Student: add grades and average method.
- ShoppingCart: add/remove items, calculate total.
- Library: add borrow/return logic.
- BankAccount: deposit, withdraw, balance with safety checks.
Practice these to solidify every OOP concept you've learned.
24️⃣ Expert Insights (For Future Learning)
- Learn design patterns (singleton, factory, observer).
- Use dataclasses ( from dataclasses import dataclass ) to auto-generate boilerplate.
- Explore typing annotations for cleaner interfaces.
- Apply inheritance in Flask, FastAPI, and Django views.
- Practice with real APIs that use OOP under the hood (Discord bots, Turtle graphics).
25️⃣ Summary 🧾
OOP turns code into living models of real systems.
- Define classes and objects.
- Use encapsulation and abstraction to organize data.
- Reuse logic through inheritance and polymorphism.
- Write cleaner, scalable, professional Python programs.
With OOP mastered, you're ready to explore Inheritance and Polymorphism in depth in the next lesson.
📋 Quick Reference — OOP
class Dog:
Define a class
def __init__(self, name):
Constructor / initialiser
Set instance variable
Dog("Rex")
Create an object
isinstance(d, Dog)
Check object type
You now understand classes, objects, attributes, methods, and the four OOP pillars. These concepts power virtually every Python framework and library.
Up next: Inheritance and Polymorphism — learn to build class hierarchies and reuse code elegantly.
Practice quiz
What is the relationship between a class and an object?
- An object is a blueprint; a class is a specific instance
- They are exactly the same thing
- A class is a blueprint/template; an object is a specific instance of it
- A class can only ever create one object
Answer: A class is a blueprint/template; an object is a specific instance of it. The class defines the blueprint (like Dog) and an object is a concrete instance (like Buddy).
Which special method runs automatically when you create a new object?
- __init__
- __str__
- __new__only
- __call__
Answer: __init__. __init__ is the constructor; it runs automatically to set up each new instance.
What does the first parameter, self, in an instance method represent?
- The class itself
- A required keyword argument you must pass manually
- The module the class lives in
- The current instance the method is called on
Answer: The current instance the method is called on. self refers to the specific object; Python passes it automatically when you call obj.method().
What is the difference between a class attribute and an instance attribute?
- Class attributes are private; instance attributes are public
- A class attribute is shared by all instances; an instance attribute belongs to one object
- There is no difference
- Instance attributes are shared; class attributes are per-object
Answer: A class attribute is shared by all instances; an instance attribute belongs to one object. Class attributes (e.g. species) are shared across instances; instance attributes (e.g. self.name) are per object.
Which dunder method is used by print(obj) to produce a human-friendly string?
- __str__
- __repr__
- __len__
- __init__
Answer: __str__. print() uses __str__ for a readable representation; __repr__ is the official/debug representation.
By Python convention, what does a single leading underscore (self._balance) signal?
- The attribute is strictly enforced as private
- It triggers name mangling
- It is 'protected' — a hint that it shouldn't be accessed directly
- It is a class attribute
Answer: It is 'protected' — a hint that it shouldn't be accessed directly. A single underscore is a convention meaning 'internal, please don't touch'; it is not strictly enforced.
In 'class Dog(Animal):', what does Dog overriding speak() achieve?
- It deletes Animal.speak permanently
- Dog inherits Animal's members but provides its own version of speak()
- It prevents Dog from being instantiated
- It calls Animal.speak twice
Answer: Dog inherits Animal's members but provides its own version of speak(). Dog inherits from Animal and overrides speak() with its own implementation.
Polymorphism in OOP means:
- A class can have only one method
- Objects cannot share method names
- Methods must all return the same type
- Different objects can respond to the same method name in their own way
Answer: Different objects can respond to the same method name in their own way. Polymorphism lets different types implement the same method (e.g. make_sound()) with different behaviour.
Which decorator marks a method that takes NO self or cls and uses no class/object data?
- @classmethod
- @staticmethod
- @property
- @instancemethod
Answer: @staticmethod. @staticmethod defines a utility function inside a class that receives neither self nor cls.
What does composition (a "has a" relationship) look like, e.g. Car and Engine?
- class Car(Engine): pass
- Engine inherits from Car
- A Car holds an Engine object as an attribute (self.engine = Engine())
- They must be the same class
Answer: A Car holds an Engine object as an attribute (self.engine = Engine()). Composition means a Car contains an Engine instance rather than inheriting from it.
Continue this course
- Previous: Modules and Packages
- Next: Inheritance and Polymorphism