Decorator thuộc tính nâng cao
Thuộc phần Lập trình hướng đối tượng trong hành trình Python của Coddy. Bài học 31 trên 64.
Các decorator thuộc tính nâng cao cho phép kiểm soát việc truy cập thuộc tính tinh vi hơn, bao gồm thuộc tính được tính toán, hàm xóa và khả năng quản lý thuộc tính toàn diện.
Đây là ví dụ về các thuộc tính được tính toán, lấy giá trị từ những thuộc tính khác:
class Rectangle:
def __init__(self, width, height):
self.width = width
self.height = height
@property
def area(self):
return self.width * self.height
@property
def perimeter(self):
return 2 * (self.width + self.height)Dùng các thuộc tính được tính toán như thuộc tính thông thường:
rect = Rectangle(5, 3)
print(rect.area) # 15, tự động tính
print(rect.perimeter) # 16, tự động tínhTạo một thuộc tính với getter, setter và deleter:
class Temperature:
def __init__(self):
self._temp = 0
@property
def temperature(self):
return self._temp
@temperature.setter
def temperature(self, value):
if value < -273.15:
raise ValueError("Temperature below absolute zero!")
self._temp = value
@temperature.deleter
def temperature(self):
print("Resetting temperature to 0")
self._temp = 0Sử dụng đầy đủ chức năng của thuộc tính:
temp = Temperature()Dùng setter kèm kiểm tra tính hợp lệ:
temp.temperature = 25
print(temp.temperature) # 25
# temp.temperature = -300 # Sẽ gây ra ValueErrorDùng hàm xóa:
del temp.temperature
print(temp.temperature) # 0Tạo một ví dụ phức tạp hơn với điểm số trong trò chơi:
class Player:
def __init__(self, name):
self.name = name
self._score = 0
self._level = 1
@property
def score(self):
return self._score
@score.setter
def score(self, value):
if value >= 0:
self._score = value
self._level = (value // 1000) + 1
else:
raise ValueError("Score cannot be negative")
@score.deleter
def score(self):
print(f"Resetting {self.name}'s progress")
self._score = 0
self._level = 1
@property
def level(self):
return self._level
player = Player("Alice")
player.score = 2500
print(f"Score: {player.score}, Level: {player.level}") # Điểm: 2500, cấp độ: 3
del player.score
print(f"Score: {player.score}, Level: {player.level}") # Điểm: 0, cấp độ: 1Đầu ra:
15
16
25
Resetting temperature to 0
0
Score: 2500, Level: 3
Resetting Alice's progress
Score: 0, Level: 1Điểm chính: Bộ trang trí thuộc tính (property decorator) nâng cao cho phép tạo thuộc tính tính toán (được tính từ dữ liệu khác), xóa thuộc tính bằng @property.deleter và kiểm soát hoàn toàn việc lấy, đặt và xóa thuộc tính. Cách này tạo ra giao diện trực quan, đồng thời duy trì khả năng xác thực dữ liệu chặt chẽ và tính đóng gói.
Thử thách
Trung bìnhTrong thử thách này, bạn sẽ triển khai lớp Rectangle với tính đóng gói phù hợp và khả năng kiểm tra tính hợp lệ của thuộc tính.
rectangle.py- Đây là tệp bạn cần chỉnh sửa, trong đó có các chú thích TODO hướng dẫn cách triển khaidriver.py- Chứa nhiều tình huống kiểm thử (không chỉnh sửa)
- Lưu các giá trị trong những thuộc tính được bảo vệ (nội bộ)
_widthvà_height - Tạo thuộc tính cho
widthvàheight, có kiểm tra tính hợp lệ (giá trị phải là số dương)- Ném ngoại lệ ValueError phù hợp như mô tả trong các TODO
- Quan trọng: Kiểm tra xem giá trị có nhỏ hơn hoặc bằng 0 hay không, rồi ném lỗi (điều này giúp đảm bảo hành vi nhất quán)
- Triển khai các thuộc tính chỉ đọc cho
areavàperimeter - Tạo thuộc tính
dimensionsvới chức năng getter, setter và deleter như mô tả trong các TODO- Quan trọng: Trong setter, hãy dùng cú pháp giải nén tuple:
width, height = dimensions
- Quan trọng: Trong setter, hãy dùng cú pháp giải nén tuple:
Tự làm thử
from rectangle import Rectangle
# Xử lý test case
test_case = input()
# Kiểm tra chức năng cơ bản
if test_case == "default_test":
rect = Rectangle(5, 3)
print(f"Width: {rect.width}, Height: {rect.height}")
print(f"Area: {rect.area}, Perimeter: {rect.perimeter}")
# Kiểm tra thuộc tính (property) dimensions
print(f"Dimensions: {rect.dimensions}")
rect.dimensions = (10, 8)
print(f"New area: {rect.area}")
# Kiểm tra việc xác thực
try:
rect.width = -2
except ValueError as e:
print(f"Validation error: {e}")
# Kiểm tra thao tác xóa
del rect.dimensions
print(f"After reset: {rect.dimensions}")
# Kiểm tra với giá trị bằng 0
elif test_case == "zero_values":
try:
rect = Rectangle(0, 5)
except ValueError as e:
print(f"Error creating rectangle: {e}")
try:
rect = Rectangle(5, 0)
except ValueError as e:
print(f"Error creating rectangle: {e}")
# Kiểm tra với giá trị âm
elif test_case == "negative_values":
rect = Rectangle(5, 3)
original_dimensions = rect.dimensions
try:
rect.dimensions = (5, -3)
except ValueError as e:
print(f"Error setting dimensions: {e}")
print(f"Dimensions after failed update: {rect.dimensions}")
print(f"Original dimensions preserved: {rect.dimensions == original_dimensions}")
# Kiểm tra với giá trị lớn
elif test_case == "large_values":
rect = Rectangle(1000000, 2000000)
print(f"Large rectangle area: {rect.area}")
print(f"Large rectangle perimeter: {rect.perimeter}")
# Kiểm tra với giá trị số thực
elif test_case == "float_values":
rect = Rectangle(3.5, 2.75)
print(f"Dimensions: {rect.dimensions}")
print(f"Area: {rect.area}")
print(f"Perimeter: {rect.perimeter}")
rect.dimensions = (1.1, 2.2)
print(f"New area with float dimensions: {rect.area}")
# Kiểm tra với lỗi kiểu dữ liệu
elif test_case == "type_errors":
try:
rect = Rectangle("5", 3)
except Exception as e:
print(f"Type error during creation: {type(e).__name__}: {e}")
rect = Rectangle(5, 3)
try:
rect.dimensions = 10 # Không phải tuple
except Exception as e:
print(f"Type error setting dimensions: {type(e).__name__}: {e}")
# Kiểm tra nhiều thao tác với thuộc tính
elif test_case == "property_operations":
rect = Rectangle(5, 10)
print(f"Initial - Width: {rect.width}, Height: {rect.height}, Area: {rect.area}")
rect.width = 8
print(f"After width change - Width: {rect.width}, Area: {rect.area}")
rect.height = 6
print(f"After height change - Height: {rect.height}, Area: {rect.area}")
rect.dimensions = (12, 9)
print(f"After dimensions change - Dimensions: {rect.dimensions}, Area: {rect.area}")
del rect.dimensions
print(f"After reset - Dimensions: {rect.dimensions}, Area: {rect.area}")
# Kiểm tra các trường hợp biên khi xác thực thuộc tính
elif test_case == "validation_edge_cases":
rect = Rectangle(5, 3)
try:
rect.width = 0
except ValueError as e:
print(f"Zero width error: {e}")
# Chấp nhận giá trị dương rất nhỏ
rect.height = 0.0001
print(f"Small height accepted: {rect.height}")
print(f"Area with small height: {rect.area}")
# Kiểm tra nhiều hình chữ nhật
elif test_case == "multiple_rectangles":
rect1 = Rectangle(5, 3)
rect2 = Rectangle(10, 2)
rect3 = Rectangle(4, 4)
print(f"Rectangle 1 - Area: {rect1.area}, Perimeter: {rect1.perimeter}")
print(f"Rectangle 2 - Area: {rect2.area}, Perimeter: {rect2.perimeter}")
print(f"Rectangle 3 - Area: {rect3.area}, Perimeter: {rect3.perimeter}")
# Thay đổi từng hình chữ nhật
rect1.width = 7
rect2.height = 5
rect3.dimensions = (6, 6)
print(f"After modifications:")
print(f"Rectangle 1 - Dimensions: {rect1.dimensions}")
print(f"Rectangle 2 - Dimensions: {rect2.dimensions}")
print(f"Rectangle 3 - Dimensions: {rect3.dimensions}")
# Kiểm tra hiệu năng với nhiều thao tác
elif test_case == "performance_test":
rect = Rectangle(5, 5)
# Thực hiện nhiều thao tác với thuộc tính
for i in range(1000):
rect.width = i % 10 + 1 # Giá trị từ 1 đến 10
rect.height = i % 5 + 1 # Giá trị từ 1 đến 5
area = rect.area # Truy cập thuộc tính được tính toán
perimeter = rect.perimeter # Truy cập thuộc tính được tính toán
dims = rect.dimensions # Truy cập phương thức getter của thuộc tính
print(f"Final state after 1000 operations:")
print(f"Width: {rect.width}, Height: {rect.height}")
print(f"Area: {rect.area}, Perimeter: {rect.perimeter}")Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.
Tất cả bài học trong Lập trình hướng đối tượng
1Nền tảng về lập trình hướng đối tượng
Tệp bên ngoàiGiới thiệu về lập trình hướng đối tượngLớp và đối tượngTham số selfPhương thứcThuộc tínhPhương thức khởi tạo (__init__)Ôn tập: máy tính đơn giản4Kế thừa
Kế thừa cơ bảnHàm super()Ghi đè phương thứcKế thừa đa lớpThứ tự phân giải phương thứcÔn tập: hệ thống phân cấp nhân viên2Decorator
Giới thiệu về decoratorDecorator thuộc tínhDecorator phương thức tĩnhDecorator phương thức lớp5Tính đa hình
Xem lại cách ghi đè phương thứcKiểu gõ vịtLớp và phương thức trừu tượngThiết kế giao diệnÔn tập: máy tính hình học8Các khái niệm OOP nâng cao
Kết hợp và kế thừaMixinPhương thức tĩnh và phương thức lớpDecorator lớpTrình quản lý ngữ cảnh3Thuộc tính của lớp
Biến của instance và biến của lớpDecorator thuộc tínhThuộc tính riêng tưÔn tập: trình quản lý tài khoản ngân hàng6Đóng gói
Thành viên public, protected, privateBộ điều chỉnh quyền truy cậpẨn thông tinDecorator thuộc tính nâng caoÔn tập: Hệ thống hồ sơ học sinhTự luyện tập: Trình biên dịch Python online