Quick Start: Get Started with Python OOP in 5 Minutes
Hey everyone, today let’s dive into Object-Oriented Programming (OOP) in Python. It might sound academic, but it’s actually a very effective way to organize code, making your projects much easier to manage and extend.
To get started quickly, we’ll create a simple NhanVien (Employee) class. A class is like a blueprint, while an object is an instance created from that blueprint.
class NhanVien:
# Constructor method
def __init__(self, ten, ma_so):
self.ten = ten # Name attribute
self.ma_so = ma_so # ID attribute
# Method to display information
def hien_thi_thong_tin(self):
print(f"Name: {self.ten}, ID: {self.ma_so}")
# Create objects from the NhanVien class
nhan_vien_1 = NhanVien("Nguyễn Văn A", "NV001")
nhan_vien_2 = NhanVien("Trần Thị B", "NV002")
# Call object methods
nhan_vien_1.hien_thi_thong_tin()
nhan_vien_2.hien_thi_thong_tin()
Run the code above, and you’ll see the output:
Name: Nguyễn Văn A, ID: NV001
Name: Trần Thị B, ID: NV002
See? With just a few lines of code, we’ve defined an “employee type” and created different “employee instances.” That’s the core idea of OOP!
Detailed Explanation: The Pillars of OOP in Python
After the quick start, let’s dive a bit deeper. OOP isn’t just about Classes and Objects. It has 4 main ‘pillars’ that help build robust code:
1. Encapsulation
Encapsulation means grouping related attributes (data) and methods (behavior) into a ‘bundle’ (class), and hiding the internal implementation details. This helps protect data from being accessed or modified externally in an unwanted way. In Python, we use naming conventions (leading underscores) to indicate which attributes should be ‘private,’ although Python doesn’t truly have private members like Java or C++.
class TaiKhoanNganHang:
def __init__(self, ten_chu_tk, so_du_ban_dau):
self.ten_chu_tk = ten_chu_tk
self.__so_du = so_du_ban_dau # 'Private' convention using double underscores
def nap_tien(self, so_tien):
if so_tien > 0:
self.__so_du += so_tien
print(f"Successfully deposited {so_tien}. Current balance: {self.__so_du}")
else:
print("Deposit amount must be greater than 0.")
def rut_tien(self, so_tien):
if 0 < so_tien <= self.__so_du:
self.__so_du -= so_tien
print(f"Successfully withdrew {so_tien}. Current balance: {self.__so_du}")
else:
print("Invalid withdrawal amount or insufficient balance.")
def xem_so_du(self):
return self.__so_du
tk = TaiKhoanNganHang("Minh Hoang", 1000)
print(f"Initial balance: {tk.xem_so_du()}")
tk.nap_tien(500)
tk.rut_tien(200)
# Attempt direct access (not recommended)
# print(tk.__so_du) # Will raise AttributeError
# Instead, access via method
print(f"Final balance: {tk.xem_so_du()}")
2. Inheritance
Inheritance allows one class (child class or subclass) to inherit attributes and methods from another class (parent class or superclass). This helps in code reuse, avoiding the need to rewrite similar parts.
class HinhDang:
def __init__(self, ten):
self.ten = ten
def mo_ta(self):
return f"This is a shape named: {self.ten}"
class HinhTron(HinhDang):
def __init__(self, ten, ban_kinh):
super().__init__(ten) # Call the parent class's constructor
self.ban_kinh = ban_kinh
def dien_tich(self):
return 3.14 * self.ban_kinh ** 2
class HinhVuong(HinhDang):
def __init__(self, ten, canh):
super().__init__(ten)
self.canh = canh
def dien_tich(self):
return self.canh ** 2
hinh_tron = HinhTron("Vòng tròn lớn", 7)
hinh_vuong = HinhVuong("Ô vuông nhỏ", 5)
print(hinh_tron.mo_ta()) # Method from parent class
print(f"Area of the circle: {hinh_tron.dien_tich()}")
print(hinh_vuong.mo_ta())
print(f"Area of the square: {hinh_vuong.dien_tich()}")
3. Polymorphism
Polymorphism means that objects of different classes can respond differently to the same message (same method name). A typical example is method overriding from a parent class.
class ConVat:
def noi(self):
pass # Empty method, to be overridden
class Cho(ConVat):
def noi(self):
return "Woof woof!"
class Meo(ConVat):
def noi(self):
return "Meow meow!"
class Vit(ConVat):
def noi(self):
return "Quack quack!"
# A function that can handle different types of objects
def tieng_keu(con_vat):
print(con_vat.noi())
cho = Cho()
meo = Meo()
vit = Vit()
tieng_keu(cho)
tieng_keu(meo)
tieng_keu(vit)
The output will be:
Woof woof!
Meow meow!
Quack quack!
Although the noi() method is called for all, each object exhibits different behavior.
4. Abstraction
Abstraction focuses on showing essential information and hiding complex details. In Python, we typically achieve abstraction through abstract classes and abstract methods by using the abc module.
from abc import ABC, abstractmethod
class PhuongTien(ABC):
@abstractmethod
def di_chuyen(self):
pass
@abstractmethod
def dung_lai(self):
pass
class XeOto(PhuongTien):
def di_chuyen(self):
print("The car is moving.")
def dung_lai(self):
print("The car has stopped.")
class XeMay(PhuongTien):
def di_chuyen(self):
print("The motorcycle is speeding recklessly.")
def dung_lai(self):
print("The motorcycle has stopped urgently.")
# p = PhuongTien() # Will raise an error because objects cannot be created from an Abstract Class
xemay = XeMay()
xemay.di_chuyen()
xemay.dung_lai()
xeto = XeOto()
xeto.di_chuyen()
xeto.dung_lai()
Advanced: Useful Techniques in Python OOP
Once the pillars are mastered, we can explore a few more ‘tricks’ to make code cleaner and more powerful.
1. The @property Decorator
The @property decorator allows you to access a method like an attribute, helping to control the reading/writing of attribute data without changing how it’s accessed externally.
class HocSinh:
def __init__(self, ten, diem):
self._ten = ten # 'Protected' convention
self._diem = diem
@property
def diem(self):
return self._diem
@diem.setter
def diem(self, new_diem):
if 0 <= new_diem <= 10:
self._diem = new_diem
else:
print("Score must be between 0 and 10.")
hs = HocSinh("Ngọc Anh", 8)
print(f"Score of {hs._ten}: {hs.diem}") # Access as attribute
hs.diem = 9.5 # Assign value as attribute
print(f"New score of {hs._ten}: {hs.diem}")
hs.diem = 12 # Will print a warning
2. Class Method and Static Method
- Class Method (
@classmethod): This method operates on the class itself, not on an instance of the class. It receivescls(instead ofself) as its first argument, pointing to the class itself. Often used to create ‘alternative constructors’. - Static Method (
@staticmethod): This method does not receiveselforcls. It’s like a regular function but is placed within a class because it’s logically related to that class, without needing to access instance or class attributes or methods.
class HinhHoc:
PI = 3.14159
def __init__(self, ten):
self.ten = ten
@classmethod
def tao_hinh_vuong_tu_chu_vi(cls, chu_vi):
canh = chu_vi / 4
return cls(f"Square with perimeter {chu_vi}", canh)
@staticmethod
def kiem_tra_so_duong(so):
return so > 0
hv = HinhHoc.tao_hinh_vuong_tu_chu_vi(20)
print(f"Shape name: {hv.ten}") # hv.canh will raise an error because it only exists in HinhVuong if inherited and added as an attribute
print(f"Check if 5 is positive: {HinhHoc.kiem_tra_so_duong(5)}")
print(f"Check if -3 is positive: {HinhHoc.kiem_tra_so_duong(-3)}")
To make the above example code clearer for classmethods, you can imagine it will be more effective when inheritance is involved and an instance of the child class needs to be created from an ‘alternative constructor’.
Practical Tips: Applying OOP Effectively in Python
OOP is a powerful tool, but it’s important to know when and how to use it effectively.
1. When to use OOP?
- When you have entities in the system with clear attributes and behaviors (e.g., Users, Products, Orders).
- When you want to reuse code and easily extend functionality (inheritance, polymorphism).
- When you need to manage the complexity of a large project, breaking it down into more logical modules.
2. Personal experience working with Python
In my experience, Python is very flexible. There are times when I need to handle strings or special patterns. When I need to quickly test regex patterns before integrating them into Python code, I often use a regex tester at toolcraft.app/en/tools/developer/regex-tester — it runs directly in the browser, no installation needed. This saves me a lot of time debugging small regex-related errors without having to rerun the entire Python script just to check a pattern.
3. Don’t overdo OOP!
Not every project requires complex OOP. For small, simple scripts that perform a few sequential tasks, applying OOP can make the code unnecessarily cumbersome. Choose the solution that fits the scale and requirements of the problem.
4. Clear code organization
Whether using OOP or functional programming, clear and readable naming for classes, methods, and variables is extremely important. I always strive to adhere to PEP 8, not just for myself but also for the team during code reviews.
Conclusion
Object-Oriented Programming in Python is a fundamental skill that helps you build large, well-structured, and maintainable applications. Through this article, I hope you have gained an overview and practiced the basic to advanced concepts of OOP. Keep practicing, read others’ code, and write a lot of code yourself, and it will ‘sink in’. Happy coding everyone!

