Bạn có thể thay đổi ý nghĩa của một toán tử trong Python tùy thuộc vào các toán hạng được sử dụng. Trong hướng dẫn này, bạn sẽ học cách sử dụng nạp chồng toán tử trong Lập trình hướng đối tượng Python.
Nạp chồng toán tử Python
Các toán tử Python hoạt động đối với các lớp dựng sẵn. Nhưng cùng một toán tử hoạt động khác nhau với các kiểu khác nhau. Ví dụ, +
toán tử sẽ thực hiện phép cộng số học trên hai số, hợp nhất hai danh sách hoặc nối hai chuỗi.
Tính năng này trong Python cho phép cùng một toán tử có nghĩa khác nhau tùy theo ngữ cảnh được gọi là nạp chồng toán tử.
Vậy điều gì sẽ xảy ra khi chúng ta sử dụng chúng với các đối tượng của một lớp do người dùng định nghĩa? Chúng ta hãy xem xét lớp sau, lớp này cố gắng mô phỏng một điểm trong hệ tọa độ 2-D.
class Point: def __init__(self, x=0, y=0): self.x = x self.y = y p1 = Point(1, 2) p2 = Point(2, 3) print(p1+p2)
Đầu ra
Traceback (lần gọi gần đây nhất): Tệp "", dòng 9, in (p1 + p2) TypeError: (các) loại toán hạng không được hỗ trợ cho +: 'Point' và 'Point'
Ở đây, chúng ta có thể thấy rằng a TypeError
đã được nâng lên, vì Python không biết cách thêm hai Point
đối tượng lại với nhau.
Tuy nhiên, chúng ta có thể đạt được nhiệm vụ này trong Python thông qua việc nạp chồng toán tử. Nhưng trước tiên, chúng ta hãy có một khái niệm về các chức năng đặc biệt.
Các hàm đặc biệt của Python
Các hàm lớp bắt đầu bằng dấu gạch dưới kép __
được gọi là các hàm đặc biệt trong Python.
Các hàm này không phải là các hàm điển hình mà chúng ta định nghĩa cho một lớp. Các __init__()
chức năng chúng ta định nghĩa ở trên là một trong số họ. Nó được gọi mỗi khi chúng ta tạo một đối tượng mới của lớp đó.
Có rất nhiều hàm đặc biệt khác trong Python. Truy cập Các hàm đặc biệt của Python để tìm hiểu thêm về chúng.
Sử dụng các hàm đặc biệt, chúng ta có thể làm cho lớp của mình tương thích với các hàm tích hợp sẵn.
>>> p1 = Point(2,3) >>> print(p1)
Giả sử chúng ta muốn print()
hàm in ra tọa độ của Point
đối tượng thay vì những gì chúng ta nhận được. Chúng ta có thể định nghĩa một __str__()
phương thức trong lớp của chúng ta để điều khiển cách đối tượng được in. Hãy xem cách chúng ta có thể đạt được điều này:
class Point: def __init__(self, x = 0, y = 0): self.x = x self.y = y def __str__(self): return "((0),(1))".format(self.x,self.y)
Bây giờ chúng ta hãy thử lại print()
chức năng.
class Point: def __init__(self, x=0, y=0): self.x = x self.y = y def __str__(self): return "((0), (1))".format(self.x, self.y) p1 = Point(2, 3) print(p1)
Đầu ra
(2, 3)
Cái đó tốt hơn. Hóa ra, phương thức tương tự này được gọi khi chúng ta sử dụng hàm tích hợp sẵn str()
hoặc format()
.
>>> str(p1) '(2,3)' >>> format(p1) '(2,3)'
Vì vậy, khi bạn sử dụng str(p1)
hoặc format(p1)
, Python gọi nội bộ p1.__str__()
phương thức. Do đó tên, chức năng đặc biệt.
Bây giờ chúng ta hãy quay trở lại quá tải toán tử.
Quá tải + Toán tử
Để nạp chồng +
toán tử, chúng ta sẽ cần triển khai __add__()
hàm trong lớp. Với sức mạnh lớn đến trách nhiệm lớn. Chúng ta có thể làm bất cứ điều gì chúng ta thích, bên trong chức năng này. Nhưng sẽ hợp lý hơn nếu trả về một Point
đối tượng của tổng tọa độ.
class Point: def __init__(self, x=0, y=0): self.x = x self.y = y def __str__(self): return "((0),(1))".format(self.x, self.y) def __add__(self, other): x = self.x + other.x y = self.y + other.y return Point(x, y)
Bây giờ hãy thử lại thao tác thêm:
class Point: def __init__(self, x=0, y=0): self.x = x self.y = y def __str__(self): return "((0),(1))".format(self.x, self.y) def __add__(self, other): x = self.x + other.x y = self.y + other.y return Point(x, y) p1 = Point(1, 2) p2 = Point(2, 3) print(p1+p2)
Đầu ra
(3,5)
Điều thực sự xảy ra là khi bạn sử dụng p1 + p2
, Python sẽ gọi p1.__add__(p2)
lần lượt là như vậy Point.__add__(p1,p2)
. Sau đó, hoạt động bổ sung được thực hiện theo cách chúng tôi đã chỉ định.
Tương tự, chúng ta cũng có thể quá tải các toán tử khác. Chức năng đặc biệt mà chúng ta cần thực hiện được lập bảng dưới đây.
Nhà điều hành | Biểu hiện | Nội bộ |
---|---|---|
Thêm vào | p1 + p2 | p1.__add__(p2) |
Phép trừ | p1 - p2 | p1.__sub__(p2) |
Phép nhân | p1 * p2 | p1.__mul__(p2) |
Quyền lực | p1 ** p2 | p1.__pow__(p2) |
Sư đoàn | p1 / p2 | p1.__truediv__(p2) |
Phân chia tầng | p1 // p2 | p1.__floordiv__(p2) |
Phần còn lại (modulo) | p1 % p2 | p1.__mod__(p2) |
Dịch chuyển sang trái theo chiều bit | p1 << p2 | p1.__lshift__(p2) |
Chuyển sang phải theo chiều bit | p1>> p2 | p1.__rshift__(p2) |
Bitwise VÀ | p1 & p2 | p1.__and__(p2) |
Bitwise HOẶC | p1 | p2 | p1.__or__(p2) |
Bitwise XOR | p1 p2 | p1.__xor__(p2) |
Bitwise KHÔNG | ~p1 | p1.__invert__() |
Quá tải các toán tử so sánh
Python không giới hạn việc nạp chồng toán tử chỉ với các toán tử số học. Chúng ta cũng có thể quá tải các toán tử so sánh.
Giả sử chúng ta muốn triển khai biểu <
tượng less than trong Point
lớp của chúng ta .
Hãy để chúng tôi so sánh độ lớn của những điểm này từ điểm gốc và trả về kết quả cho mục đích này. Nó có thể được thực hiện như sau.
# overloading the less than operator class Point: def __init__(self, x=0, y=0): self.x = x self.y = y def __str__(self): return "((0),(1))".format(self.x, self.y) def __lt__(self, other): self_mag = (self.x ** 2) + (self.y ** 2) other_mag = (other.x ** 2) + (other.y ** 2) return self_mag < other_mag p1 = Point(1,1) p2 = Point(-2,-3) p3 = Point(1,-1) # use less than print(p1
Output
True False False
Similarly, the special functions that we need to implement, to overload other comparison operators are tabulated below.
Operator Expression Internally
Less than p1 < p2
p1.__lt__(p2)
Less than or equal to p1 <= p2
p1.__le__(p2)
Equal to p1 == p2
p1.__eq__(p2)
Not equal to p1 != p2
p1.__ne__(p2)
Greater than p1> p2
p1.__gt__(p2)
Greater than or equal to p1>= p2
p1.__ge__(p2)