0% found this document useful (0 votes)
2 views9 pages

OOP in Python Guide

This document is a comprehensive guide to Object-Oriented Programming (OOP) in Python, covering fundamental concepts such as classes, objects, encapsulation, inheritance, polymorphism, and abstraction. It includes practical examples, advanced topics like dunder methods, property decorators, and abstract base classes, as well as design principles like SOLID. The guide aims to help readers understand and apply OOP principles effectively in their Python programming.
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
2 views9 pages

OOP in Python Guide

This document is a comprehensive guide to Object-Oriented Programming (OOP) in Python, covering fundamental concepts such as classes, objects, encapsulation, inheritance, polymorphism, and abstraction. It includes practical examples, advanced topics like dunder methods, property decorators, and abstract base classes, as well as design principles like SOLID. The guide aims to help readers understand and apply OOP principles effectively in their Python programming.
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

Object-Oriented Programming

in Python
Theory + Practical Code — From Basics to Advanced

A concise, code-driven guide covering classes, objects, the four pillars of OOP, dunder methods, and
advanced patterns — with runnable Python examples throughout.
Contents
• 1. What is OOP? (Theory)
• 2. Classes and Objects
• 3. The __init__ Method and Attributes
• 4. Instance vs Class Attributes/Methods
• 5. Encapsulation
• 6. Inheritance
• 7. Polymorphism
• 8. Abstraction
• 9. Dunder (Magic) Methods
• 10. Composition vs Inheritance
• 11. Advanced: Property Decorators
• 12. Advanced: Abstract Base Classes
• 13. Advanced: Class Design Principles (SOLID, brief)
• 14. Quick Reference Cheat Sheet
1. What is OOP?
Object-Oriented Programming (OOP) is a way of structuring code around objects — bundles of data
(attributes) and behavior (methods) — instead of just functions acting on raw data. Python is a fully
object-oriented language: even integers, strings, and functions are objects.

The Four Pillars


• Encapsulation — bundling data and methods together, and controlling access to internals.
• Inheritance — creating new classes that reuse and extend existing ones.
• Polymorphism — using a single interface for different underlying data types/classes.
• Abstraction — hiding complex implementation details behind a simple interface.
■ Why bother? OOP models real-world relationships naturally, reduces code duplication, and makes large
codebases easier to extend and maintain.

2. Classes and Objects


A class is a blueprint. An object (or instance) is a concrete thing built from that blueprint. Think: class = 'Car'
design, object = your actual car.
class Dog:
pass # empty class body

my_dog = Dog() # my_dog is an object (instance) of Dog


print(type(my_dog)) # <class '__main__.Dog'>
print(isinstance(my_dog, Dog)) # True

3. The __init__ Method and Attributes


__init__ is the constructor — it runs automatically when an object is created, and is used to set up initial
attributes (data stored on the object). self refers to the specific instance being created/used.
class Dog:
def __init__(self, name, breed):
[Link] = name # instance attribute
[Link] = breed

def bark(self): # instance method


return f"{[Link]} says Woof!"

rex = Dog("Rex", "Labrador")


print([Link]) # Rex
print([Link]()) # Rex says Woof!

4. Instance vs Class Attributes/Methods


Class attributes are shared by all instances. Instance attributes belong to one object only. Similarly,
@classmethod operates on the class, and @staticmethod is a plain function namespaced inside the
class.
class Dog:
species = "Canis familiaris" # class attribute (shared)

def __init__(self, name):


[Link] = name # instance attribute

@classmethod
def from_string(cls, data): # alternate constructor
name = [Link]("-")[0]
return cls(name)

@staticmethod
def is_adult(age_years): # utility, no self/cls data needed
return age_years >= 1

print([Link]) # Canis familiaris


d = Dog.from_string("Buddy-3yrs")
print([Link]) # Buddy
print(Dog.is_adult(2)) # True

5. Encapsulation
Encapsulation restricts direct access to internal state. Python has no true 'private' keyword, but uses naming
conventions: _single_underscore = 'internal use, please don't touch', and __double_underscore =
name-mangled to discourage accidental access.
class BankAccount:
def __init__(self, balance):
self.__balance = balance # name-mangled to _BankAccount__balance

def deposit(self, amount):


if amount > 0:
self.__balance += amount

def get_balance(self):
return self.__balance

acc = BankAccount(100)
[Link](50)
print(acc.get_balance()) # 150
# print(acc.__balance) # AttributeError - not directly accessible
6. Inheritance
Inheritance lets a child class reuse and extend a parent class. Use super() to call the parent's
implementation.
class Animal:
def __init__(self, name):
[Link] = name

def speak(self):
return f"{[Link]} makes a sound"

class Cat(Animal): # Cat inherits from Animal


def speak(self): # method overriding
return f"{[Link]} says Meow"

class Kitten(Cat): # multilevel inheritance


def speak(self):
base = super().speak() # call parent method
return base + " (softly, it's a kitten)"

a = Animal("Generic")
c = Cat("Whiskers")
k = Kitten("Tiny")
print([Link]()) # Generic makes a sound
print([Link]()) # Whiskers says Meow
print([Link]()) # Tiny says Meow (softly, it's a kitten)

■ Python also supports multiple inheritance: class C(A, B). Method Resolution Order (MRO) decides which parent's
method wins — check with ClassName.__mro__.

7. Polymorphism
Polymorphism means the same interface behaves differently depending on the object. Python supports this
naturally via duck typing: 'if it walks like a duck and quacks like a duck...' — no explicit interface required.
class Cat:
def speak(self): return "Meow"

class Dog:
def speak(self): return "Woof"

def animal_sound(animal):
print([Link]()) # works for ANY object with .speak()

for a in [Cat(), Dog()]:


animal_sound(a) # Meow, then Woof

8. Abstraction
Abstraction hides implementation detail behind a simple interface, exposing only what's necessary. In
Python this is formalized with the abc module.
from abc import ABC, abstractmethod
class Shape(ABC):
@abstractmethod
def area(self):
... # no implementation - forces subclasses to define it

class Rectangle(Shape):
def __init__(self, w, h):
self.w, self.h = w, h

def area(self):
return self.w * self.h

# Shape() # TypeError: Can't instantiate abstract class


r = Rectangle(4, 5)
print([Link]()) # 20

9. Dunder (Magic) Methods


Double-underscore methods let your objects work with Python's built-in syntax (printing, operators, length,
iteration, etc.).
class Point:
def __init__(self, x, y):
self.x, self.y = x, y

def __repr__(self): # developer-facing representation


return f"Point({self.x}, {self.y})"

def __eq__(self, other): # enables == comparison


return self.x == other.x and self.y == other.y

def __add__(self, other): # enables + operator


return Point(self.x + other.x, self.y + other.y)

def __len__(self): # enables len()


return int((self.x**2 + self.y**2) ** 0.5)

p1, p2 = Point(1, 2), Point(3, 4)


print(p1 + p2) # Point(4, 6)
print(p1 == Point(1,2)) # True
print(len(p1)) # 2

10. Composition vs Inheritance


Composition builds objects out of other objects ('has-a' relationship) instead of extending a base class
('is-a'). It's often more flexible than deep inheritance chains — the common guideline is 'favor composition
over inheritance'.
class Engine:
def start(self):
return "Engine starting..."

class Car:
def __init__(self):
[Link] = Engine() # Car "has-a" Engine (composition)
def start(self):
return [Link]()

my_car = Car()
print(my_car.start()) # Engine starting...
11. Advanced: Property Decorators
@property lets you expose a method as if it were an attribute — useful for computed values or validated
setters, keeping a clean public API.
class Circle:
def __init__(self, radius):
self._radius = radius

@property
def radius(self):
return self._radius

@[Link]
def radius(self, value):
if value <= 0:
raise ValueError("Radius must be positive")
self._radius = value

@property
def area(self): # read-only computed property
return 3.14159 * self._radius ** 2

c = Circle(5)
print([Link]) # 78.53975
[Link] = 10 # goes through the setter's validation
print([Link]) # 314.159

12. Advanced: Abstract Base Classes & Interfaces


ABCs can define a shared contract across many unrelated classes, enabling polymorphism with
compile-time-like safety (enforced at instantiation).
from abc import ABC, abstractmethod

class PaymentMethod(ABC):
@abstractmethod
def pay(self, amount): ...

class CreditCard(PaymentMethod):
def pay(self, amount):
return f"Charged ${amount} to credit card"

class PayPal(PaymentMethod):
def pay(self, amount):
return f"Paid ${amount} via PayPal"

def checkout(method: PaymentMethod, amount):


print([Link](amount)) # polymorphic call

checkout(CreditCard(), 50)
checkout(PayPal(), 75)

13. Advanced: Class Design Principles (Brief)


The SOLID principles guide clean OOP design in any language, including Python:

Principle Meaning

S Single Responsibility A class should have one reason to change.

O Open/Closed Open for extension, closed for modification.

L Liskov Substitution Subclasses should be usable wherever the parent is expected.

I Interface Segregation Prefer many small, specific interfaces over one large one.

D Dependency Inversion Depend on abstractions, not concrete implementations.

14. Quick Reference Cheat Sheet


Concept Keyword / Syntax

Define class class Name: ...

Constructor def __init__(self, ...):

Instance method def method(self, ...):

Class method @classmethod / def m(cls, ...):

Static method @staticmethod / def m(...):

Inheritance class Child(Parent):

Call parent method super().method()

Abstract class from abc import ABC, abstractmethod

Property (getter) @property

Property (setter) @[Link]

String repr def __repr__(self):

Operator overload def __add__(self, other):

Private-ish attribute self.__attr (name-mangled)

Summary: Start with classes/objects and __init__, layer in encapsulation, inheritance, polymorphism and
abstraction, then reach for dunder methods, properties, and ABCs as your designs grow more advanced.
Practice by rewriting a small program you already know using these patterns.

You might also like