Trong lập trình hướng đối tượng Python, ba decorator @classmethod, @staticmethod và @property giúp định nghĩa hành vi đặc biệt cho các phương thức trong lớp. Dưới đây là cách chúng hoạt động và khác biệt giữa chúng.
Phương thức tĩnh (@staticmethod)
Được dùng khi bạn muốn một hàm thuộc về lớp nhưng không cần truy cập đến trạng thái của lớp hay đối tượng. Không yêu cầu tham số mặc định như self hay cls.
class Calculator:
@staticmethod
def multiply(a, b):
return a * b
# Gọi qua lớp
print(Calculator.multiply(5, 3)) # 15
# Gọi qua đối tượng
calc = Calculator()
print(calc.multiply(4, 6)) # 24
Lưu ý: Vì không nhận self, nên không thể truy cập thuộc tính hay phương thức của đối tượng. Nếu cần, bạn phải truyền đối tượng vào thủ công.
class Animal:
def __init__(self, species):
self.species = species
@staticmethod
def describe(animal_instance, food):
print(f"{animal_instance.species} đang ăn {food}")
dog = Animal("Chó")
Animal.describe(dog, "xương") # Chó đang ăn xương
Phương thức lớp (@classmethod)
Nhận tham số đầu tiên là cls — đại diện cho chính lớp đó. Dùng để tạo factory method hoặc truy cập thuộc tính/métod cấp lớp.
class Vehicle:
brand = "Toyota"
@classmethod
def show_brand(cls):
print(f"Thương hiệu: {cls.brand}")
@classmethod
def create_default(cls):
return cls()
car = Vehicle.create_default()
Vehicle.show_brand() # Thương hiệu: Toyota
car.show_brand() # Thương hiệu: Toyota
Bạn cũng có thể gọi các phương thức khác trong lớp thông qua cls:
class Message:
@classmethod
def send(cls, text):
instance = cls()
instance.display(text)
def display(self, msg):
print(f"[Thông báo]: {msg}")
Message.send("Xin chào!") # [Thông báo]: Xin chào!
Quan trọng: @classmethod chỉ truy cập được biến lớp, không truy cập được biến thực thể (instance variable).
Thuộc tính (@property)
Biến một phương thức thành thuộc tính, cho phép truy cập như biến bình thường (không cần dấu ngoặc). Thường dùng để kiểm soát việc đọc/ghi/xóa dữ liệu.
class Circle:
def __init__(self, radius):
self._radius = radius
@property
def radius(self):
return self._radius
@radius.setter
def radius(self, value):
if value > 0:
self._radius = value
else:
raise ValueError("Bán kính phải lớn hơn 0")
@radius.deleter
def radius(self):
self._radius = 0
c = Circle(5)
print(c.radius) # 5 (gọi như thuộc tính)
c.radius = 10 # Gán giá trị mới
print(c.radius) # 10
del c.radius # Xóa (gán 0)
print(c.radius) # 0
Tóm tắt:
@property: getter — truy xuất giá trị@.setter: setter — gán giá trị mới@.deleter: deleter — xử lý khi xóa thuộc tính