Nạp chồng toán tử
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 34 trên 64.
Nạp chồng toán tử cho phép các lớp của bạn hoạt động với các toán tử tích hợp sẵn của Python (+, -, *, v.v.) bằng cách triển khai các phương thức ma thuật đặc biệt.
Đây là ví dụ về một lớp có nạp chồng toán tử:
class Vector:
def __init__(self, x, y):
self.x = x
self.y = y
def __add__(self, other):
return Vector(self.x + other.x, self.y + other.y)
def __mul__(self, scalar):
return Vector(self.x * scalar, self.y * scalar)
def __str__(self):
return f"Vector({self.x}, {self.y})"Phương thức __add__ xác định điều gì xảy ra khi bạn dùng toán tử +:
v1 = Vector(2, 3)
v2 = Vector(5, 7)
result = v1 + v2 # Gọi v1.__add__(v2)
print(result)Phương thức __mul__ quy định điều gì xảy ra khi bạn dùng toán tử *:
v1 = Vector(2, 3)
scaled = v1 * 3 # Gọi v1.__mul__(3)
print(scaled)Đầu ra:
Vector(7, 10)
Vector(6, 9)Thêm các toán tử so sánh:
class Vector:
def __init__(self, x, y):
self.x = x
self.y = y
def __add__(self, other):
return Vector(self.x + other.x, self.y + other.y)
def __eq__(self, other):
return self.x == other.x and self.y == other.y
def __str__(self):
return f"Vector({self.x}, {self.y})"
v1 = Vector(2, 3)
v2 = Vector(2, 3)
v3 = Vector(1, 1)
print(v1 == v2) # True: gọi v1.__eq__(v2)
print(v1 == v3) # FalseĐiểm chính: Nạp chồng toán tử (operator overloading) dùng các phương thức đặc biệt như __add__ (+), __sub__ (-), __mul__ (*), __eq__ (==) để xác định cách các toán tử hoạt động với đối tượng của bạn. Nhờ vậy, các lớp hoạt động tự nhiên với những toán tử tích hợp sẵn của Python.
Thử thách
Trung bìnhTrong thử thách này, bạn sẽ triển khai lớp Money để biểu diễn các khoản tiền và nạp chồng toán tử một cách toàn diện. Lời giải của bạn sẽ được kiểm tra kỹ lưỡng bằng một bộ test case toàn diện.
money.py, đây là tệp duy nhất bạn cần chỉnh sửa. Tệp chứa định nghĩa lớp cùng các chú thích TODO hướng dẫn bạn triển khai.driver.py, tệp này chứa nhiều kịch bản kiểm thử để xác thực lời giải của bạn (không chỉnh sửa).
Triển khai lớp Money với các tính năng sau:
- Hàm khởi tạo nhận
amount(số thực) vàcurrency(chuỗi) - Cộng (
+) các đối tượng Money có cùng đơn vị tiền tệ - Nhân (
*) với một số để thay đổi quy mô khoản tiền - So sánh bằng (
==) giữa các đối tượng Money - Biểu diễn chuỗi theo định dạng “X.XX CUR”
Tự làm thử
from money import Money
# Xử lý test case
test_case = input()
def test_basic_functionality():
# Kiểm tra khởi tạo và biểu diễn dưới dạng chuỗi (string)
m1 = Money(10.0, "USD")
assert str(m1) == "10.00 USD", f"__str__ method failed, got {str(m1)}"
# Kiểm tra phép cộng
m2 = Money(20.0, "USD")
m3 = m1 + m2
assert str(m3) == "30.00 USD", f"Addition failed, got {str(m3)}"
# Kiểm tra phép cộng giữa các đơn vị tiền tệ khác nhau
m4 = Money(20.0, "EUR")
try:
m5 = m1 + m4
assert False, "Adding different currencies should raise an error"
except ValueError as e:
assert str(e) == "Cannot add different currencies", f"Wrong error message: {str(e)}"
# Kiểm tra phép nhân
m6 = m1 * 3
assert str(m6) == "30.00 USD", f"Multiplication failed, got {str(m6)}"
# Kiểm tra tính bằng nhau
assert m1 == Money(10.0, "USD"), "Equality test failed"
assert m1 != m2, "Inequality test failed"
print("All basic functionality tests passed!")
def test_zero_values():
# Kiểm tra với số tiền bằng 0
m1 = Money(0.0, "USD")
assert str(m1) == "0.00 USD", f"Zero amount string representation failed, got {str(m1)}"
# Kiểm tra phép cộng với 0
m2 = Money(10.0, "USD")
m3 = m1 + m2
assert str(m3) == "10.00 USD", f"Addition with zero failed, got {str(m3)}"
# Kiểm tra phép nhân với 0
m4 = m2 * 0
assert str(m4) == "0.00 USD", f"Multiplication by zero failed, got {str(m4)}"
# Kiểm tra tính bằng nhau khi số tiền bằng 0
assert m1 == Money(0.0, "USD"), "Equality with zero amount failed"
assert m1 != m2, "Inequality with zero amount failed"
print("All zero value tests passed!")
def test_negative_values():
# Kiểm tra với số tiền âm
m1 = Money(-10.0, "USD")
assert str(m1) == "-10.00 USD", f"Negative amount string representation failed, got {str(m1)}"
# Kiểm tra phép cộng với số tiền âm
m2 = Money(20.0, "USD")
m3 = m1 + m2
assert str(m3) == "10.00 USD", f"Addition with negative amount failed, got {str(m3)}"
m4 = Money(-5.0, "USD")
m5 = m1 + m4
assert str(m5) == "-15.00 USD", f"Addition of two negative amounts failed, got {str(m5)}"
# Kiểm tra phép nhân với một số âm
m6 = m2 * -2
assert str(m6) == "-40.00 USD", f"Multiplication by negative scalar failed, got {str(m6)}"
# Kiểm tra tính bằng nhau của các số tiền âm
assert m1 == Money(-10.0, "USD"), "Equality with negative amount failed"
assert m1 != m2, "Inequality with negative amount failed"
print("All negative value tests passed!")
def test_large_values():
# Kiểm tra với các số tiền rất lớn
m1 = Money(1000000.0, "USD")
assert str(m1) == "1000000.00 USD", f"Large amount string representation failed, got {str(m1)}"
# Kiểm tra phép cộng các số tiền lớn
m2 = Money(2000000.0, "USD")
m3 = m1 + m2
assert str(m3) == "3000000.00 USD", f"Addition with large amounts failed, got {str(m3)}"
# Kiểm tra phép nhân với một số lớn
m4 = m1 * 1000
assert str(m4) == "1000000000.00 USD", f"Multiplication with large scalar failed, got {str(m4)}"
print("All large value tests passed!")
def test_precision():
# Kiểm tra với các số tiền có phần thập phân
m1 = Money(10.25, "USD")
assert str(m1) == "10.25 USD", f"Fractional amount string representation failed, got {str(m1)}"
m2 = Money(10.2, "USD")
assert str(m2) == "10.20 USD", f"Two decimal place formatting failed, got {str(m2)}"
# Kiểm tra phép cộng các số tiền có phần thập phân
m3 = Money(0.75, "USD")
m4 = m1 + m3
assert str(m4) == "11.00 USD", f"Addition with fractional amounts failed, got {str(m4)}"
# Kiểm tra phép nhân với một số có phần thập phân
m5 = m1 * 0.4
assert str(m5) == "4.10 USD", f"Multiplication with fractional scalar failed, got {str(m5)}"
print("All precision tests passed!")
def test_type_validation():
try:
# Các phép toán này không được gây ra lỗi
m1 = Money(10.0, "USD")
m2 = m1 * 2
m3 = m1 * 2.5
# Kiểm tra tính bằng nhau giữa các kiểu dữ liệu khác nhau
assert (m1 == "10.00 USD") == False, "Equality with string should return False"
assert (m1 == 10.0) == False, "Equality with number should return False"
print("All type validation tests passed!")
except Exception as e:
print(f"Type validation test failed: {e}")
def test_currency_case_sensitivity():
# Kiểm tra phân biệt chữ hoa và chữ thường trong mã tiền tệ
m1 = Money(10.0, "USD")
m2 = Money(10.0, "usd")
# Mã tiền tệ phải phân biệt chữ hoa và chữ thường
assert m1 != m2, "Currency comparison should be case-sensitive"
# Cộng các đơn vị tiền tệ khác nhau về chữ hoa, chữ thường phải báo lỗi
try:
m3 = m1 + m2
assert False, "Adding different currency cases should raise an error"
except ValueError as e:
assert str(e) == "Cannot add different currencies", f"Wrong error message: {str(e)}"
print("All currency case sensitivity tests passed!")
def test_performance():
# Tạo nhiều đối tượng Money và thực hiện các phép tính
base = Money(1.0, "USD")
result = base
# Thực hiện 1000 phép cộng
for i in range(1000):
result = result + Money(1.0, "USD")
assert str(result) == "1001.00 USD", f"Performance test addition failed, got {str(result)}"
# Thực hiện 10 phép nhân
result = base
for i in range(10):
result = result * 2
assert str(result) == "1024.00 USD", f"Performance test multiplication failed, got {str(result)}"
print("All performance tests passed!")
# Chạy bài kiểm tra phù hợp dựa trên đầu vào
if test_case == "basic_test":
test_basic_functionality()
elif test_case == "zero_values":
test_zero_values()
elif test_case == "negative_values":
test_negative_values()
elif test_case == "large_values":
test_large_values()
elif test_case == "precision":
test_precision()
elif test_case == "type_validation":
test_type_validation()
elif test_case == "currency_case":
test_currency_case_sensitivity()
elif test_case == "performance":
test_performance()
else:
print(f"Unknown test case: {test_case}")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ên7Phương thức đặc biệt
Giới thiệu về phương thức ma thuậtNạp chồng toán tửPhương thức ma thuật của vùng chứaÔn tập: danh sách tùy chỉnh2Decorator
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ảnhTự luyện tập: Trình biên dịch Python online