Skip to Content
Python🎯 Python OOPSpecial Methods (Magic Methods)

Special Methods (Magic Methods)

Special Methods là gì?

Special Methods (còn gọi là Magic Methods hoặc Dunder Methods) là các phương thức đặc biệt trong Python với tên bắt đầu và kết thúc bằng __ (double underscore).

Ví dụ: __init__, __str__, __add__, __len__

Tại sao gọi là “Magic”?

Các phương thức này được Python gọi tự động trong một số tình huống đặc biệt:

  • __init__() được gọi khi tạo object
  • __str__() được gọi khi dùng print()
  • __add__() được gọi khi dùng toán tử +
  • __len__() được gọi khi dùng hàm len()

Các Special Methods phổ biến

1. Object Initialization và Representation

__init__(self, ...) - Constructor

Khởi tạo object khi tạo mới.

class Person: def __init__(self, name, age): self.name = name self.age = age person = Person("An", 20) # __init__ được gọi tự động

__str__(self) - String Representation (cho người dùng)

Trả về chuỗi khi dùng print() hoặc str().

class Person: def __init__(self, name, age): self.name = name self.age = age def __str__(self): return f"{self.name}, {self.age} tuổi" person = Person("An", 20) print(person) # An, 20 tuổi

__repr__(self) - Official Representation (cho lập trình viên)

Trả về chuỗi đại diện chính thức của object.

class Person: def __init__(self, name, age): self.name = name self.age = age def __repr__(self): return f"Person(name='{self.name}', age={self.age})" def __str__(self): return f"{self.name}, {self.age} tuổi" person = Person("An", 20) print(person) # An, 20 tuổi (__str__) print(repr(person)) # Person(name='An', age=20) (__repr__)

2. Comparison Operators (Toán tử so sánh)

class Student: def __init__(self, name, gpa): self.name = name self.gpa = gpa def __eq__(self, other): """Equal: ==""" return self.gpa == other.gpa def __ne__(self, other): """Not equal: !=""" return self.gpa != other.gpa def __lt__(self, other): """Less than: <""" return self.gpa < other.gpa def __le__(self, other): """Less than or equal: <=""" return self.gpa <= other.gpa def __gt__(self, other): """Greater than: >""" return self.gpa > other.gpa def __ge__(self, other): """Greater than or equal: >=""" return self.gpa >= other.gpa def __str__(self): return f"{self.name} (GPA: {self.gpa})" s1 = Student("An", 3.5) s2 = Student("Bình", 3.2) s3 = Student("Cường", 3.5) print(s1 == s3) # True (__eq__) print(s1 != s2) # True (__ne__) print(s1 > s2) # True (__gt__) print(s1 <= s3) # True (__le__)

3. Arithmetic Operators (Toán tử số học)

class Vector: def __init__(self, x, y): self.x = x self.y = y def __add__(self, other): """Addition: +""" return Vector(self.x + other.x, self.y + other.y) def __sub__(self, other): """Subtraction: -""" return Vector(self.x - other.x, self.y - other.y) def __mul__(self, scalar): """Multiplication: *""" if isinstance(scalar, (int, float)): return Vector(self.x * scalar, self.y * scalar) raise TypeError("Phải nhân với số") def __truediv__(self, scalar): """Division: /""" if isinstance(scalar, (int, float)): return Vector(self.x / scalar, self.y / scalar) raise TypeError("Phải chia cho số") def __str__(self): return f"Vector({self.x}, {self.y})" v1 = Vector(4, 2) v2 = Vector(2, 1) print(v1 + v2) # Vector(6, 3) print(v1 - v2) # Vector(2, 1) print(v1 * 3) # Vector(12, 6) print(v1 / 2) # Vector(2.0, 1.0)

4. Container Methods

__len__(self) - Length

class Playlist: def __init__(self, name): self.name = name self.songs = [] def add_song(self, song): self.songs.append(song) def __len__(self): return len(self.songs) playlist = Playlist("My Favorites") playlist.add_song("Song 1") playlist.add_song("Song 2") playlist.add_song("Song 3") print(len(playlist)) # 3

__getitem__(self, key)__setitem__(self, key, value) - Indexing

class ShoppingCart: def __init__(self): self.items = [] def add_item(self, item): self.items.append(item) def __getitem__(self, index): """Cho phép cart[index]""" return self.items[index] def __setitem__(self, index, value): """Cho phép cart[index] = value""" self.items[index] = value def __len__(self): return len(self.items) cart = ShoppingCart() cart.add_item("Laptop") cart.add_item("Mouse") cart.add_item("Keyboard") print(cart[0]) # Laptop (__getitem__) print(cart[1]) # Mouse cart[1] = "Gaming Mouse" # __setitem__ print(cart[1]) # Gaming Mouse # Có thể dùng trong vòng lặp for item in cart: print(item)

__contains__(self, item) - Membership Test

class Team: def __init__(self, name): self.name = name self.members = [] def add_member(self, member): self.members.append(member) def __contains__(self, member): """Cho phép dùng 'in'""" return member in self.members team = Team("Dev Team") team.add_member("An") team.add_member("Bình") print("An" in team) # True print("Cường" in team) # False

5. Iteration

__iter__(self)__next__(self) - Iterator Protocol

class Countdown: def __init__(self, start): self.start = start def __iter__(self): self.current = self.start return self def __next__(self): if self.current <= 0: raise StopIteration self.current -= 1 return self.current + 1 # Sử dụng countdown = Countdown(5) for num in countdown: print(num) # 5, 4, 3, 2, 1

6. Context Manager

__enter__(self)__exit__(self) - Dùng với with

class FileManager: def __init__(self, filename, mode): self.filename = filename self.mode = mode self.file = None def __enter__(self): """Được gọi khi vào block with""" self.file = open(self.filename, self.mode) return self.file def __exit__(self, exc_type, exc_val, exc_tb): """Được gọi khi ra khỏi block with""" if self.file: self.file.close() # Sử dụng with FileManager('test.txt', 'w') as f: f.write('Hello World') # File tự động đóng sau khi ra khỏi block

7. Callable Objects

__call__(self) - Gọi object như hàm

class Multiplier: def __init__(self, factor): self.factor = factor def __call__(self, value): """Cho phép gọi object như hàm""" return value * self.factor double = Multiplier(2) triple = Multiplier(3) print(double(5)) # 10 print(triple(5)) # 15

Ví dụ thực tế: Class Money

class Money: def __init__(self, amount, currency="VND"): self.amount = amount self.currency = currency def __str__(self): """String representation""" return f"{self.amount:,.0f} {self.currency}" def __repr__(self): """Official representation""" return f"Money({self.amount}, '{self.currency}')" def __add__(self, other): """Addition""" if isinstance(other, Money): if self.currency != other.currency: raise ValueError("Không thể cộng hai đơn vị tiền tệ khác nhau!") return Money(self.amount + other.amount, self.currency) elif isinstance(other, (int, float)): return Money(self.amount + other, self.currency) raise TypeError("Không thể cộng Money với kiểu này") def __sub__(self, other): """Subtraction""" if isinstance(other, Money): if self.currency != other.currency: raise ValueError("Không thể trừ hai đơn vị tiền tệ khác nhau!") return Money(self.amount - other.amount, self.currency) elif isinstance(other, (int, float)): return Money(self.amount - other, self.currency) raise TypeError("Không thể trừ Money với kiểu này") def __mul__(self, scalar): """Multiplication""" if isinstance(scalar, (int, float)): return Money(self.amount * scalar, self.currency) raise TypeError("Chỉ có thể nhân Money với số") def __truediv__(self, scalar): """Division""" if isinstance(scalar, (int, float)): return Money(self.amount / scalar, self.currency) raise TypeError("Chỉ có thể chia Money cho số") def __eq__(self, other): """Equal""" if isinstance(other, Money): return self.amount == other.amount and self.currency == other.currency return False def __lt__(self, other): """Less than""" if isinstance(other, Money): if self.currency != other.currency: raise ValueError("Không thể so sánh hai đơn vị tiền tệ khác nhau!") return self.amount < other.amount raise TypeError("Không thể so sánh Money với kiểu này") def __le__(self, other): """Less than or equal""" return self == other or self < other def __bool__(self): """Boolean conversion""" return self.amount > 0 # Sử dụng m1 = Money(100000) m2 = Money(50000) print(m1) # 100,000 VND print(repr(m1)) # Money(100000, 'VND') m3 = m1 + m2 print(m3) # 150,000 VND m4 = m1 - m2 print(m4) # 50,000 VND m5 = m1 * 2 print(m5) # 200,000 VND m6 = m1 / 2 print(m6) # 50,000 VND print(m1 > m2) # True print(m1 == m2) # False if m1: print("Có tiền!") # Có tiền!

Ví dụ: Class Range (tự implement)

class MyRange: """Tự implement class tương tự range() của Python""" def __init__(self, start, stop=None, step=1): if stop is None: self.start = 0 self.stop = start else: self.start = start self.stop = stop self.step = step def __iter__(self): self.current = self.start return self def __next__(self): if (self.step > 0 and self.current >= self.stop) or \ (self.step < 0 and self.current <= self.stop): raise StopIteration value = self.current self.current += self.step return value def __len__(self): return max(0, (self.stop - self.start + self.step - 1) // self.step) def __getitem__(self, index): if index < 0 or index >= len(self): raise IndexError("Index out of range") return self.start + index * self.step def __contains__(self, value): if self.step > 0: return self.start <= value < self.stop and \ (value - self.start) % self.step == 0 else: return self.stop < value <= self.start and \ (value - self.start) % self.step == 0 def __str__(self): return f"MyRange({self.start}, {self.stop}, {self.step})" # Sử dụng r = MyRange(0, 10, 2) print(r) # MyRange(0, 10, 2) print(len(r)) # 5 print(r[2]) # 4 print(4 in r) # True print(5 in r) # False for num in r: print(num) # 0, 2, 4, 6, 8

Bảng tổng hợp Special Methods

LoạiMethodMô tả
Khởi tạo__init__(self, ...)Constructor
__new__(cls, ...)Tạo instance mới
__del__(self)Destructor
Representation__str__(self)str(), print()
__repr__(self)repr(), representation chính thức
So sánh__eq__(self, other)==
__ne__(self, other)!=
__lt__(self, other)<
__le__(self, other)<=
__gt__(self, other)>
__ge__(self, other)>=
Toán tử số học__add__(self, other)+
__sub__(self, other)-
__mul__(self, other)*
__truediv__(self, other)/
__floordiv__(self, other)//
__mod__(self, other)%
__pow__(self, other)**
Container__len__(self)len()
__getitem__(self, key)obj[key]
__setitem__(self, key, value)obj[key] = value
__delitem__(self, key)del obj[key]
__contains__(self, item)in
Iteration__iter__(self)Iterator
__next__(self)Next item
Callable__call__(self, ...)obj()
Context Manager__enter__(self)with statement entry
__exit__(self, ...)with statement exit
Attribute Access__getattr__(self, name)Get attribute
__setattr__(self, name, value)Set attribute
__delattr__(self, name)Delete attribute

Tổng kết

  • Special Methods cho phép class của bạn hoạt động giống built-in types
  • Bắt đầu và kết thúc bằng __ (dunder - double underscore)
  • Được Python gọi tự động trong các tình huống đặc biệt
  • Giúp code trở nên Pythonic và trực quan hơn
  • Cho phép overload operators và implement protocols

Chúc mừng bạn đã hoàn thành series về OOP trong Python! 🎉

Last updated on