本篇的主角正是“点”,今天要用运算符重载来,把它玩出“点”花样来!那什么是运算符重载呢?
运算符重载
运算符重载是面向对象编程中的一个概念,它允许程序员为自定义类型(如类或结构体)定义特定的运算符行为,使得这些类的实例可以使用语言中预定义的运算符。在Python等编程语言中,运算符重载是一种强大的特性,它使得我们可以用更加自然和直观的方式处理自定义类型。在实际编程中,我们应该根据需要合理使用这一特性,以提高代码的质量和效率。
主角点类
class Point 这个类很简单,就两个属性:横坐标x和纵坐标y。
class Point:
def __init__(self, x=0, y=0):
self.x, self.y = x, y
def __repr__(self):
return f'Point({self.x}, {self.y})'
def __str__(self):
return f'({self.x}, {self.y})'
测试:
a = Point()
a
Point(0, 0)
str(a)
‘(0, 0)’
b = Point(2, 5)
b
Point(2, 5)
对于只需要整数坐标的类,比如二维数组的行列坐标,本文主要讨论整数坐标值的坐标,可以在类初始化函数里加上类型判断:
class Point:
def __init__(self, x=0, y=0):
self.x, self.y = x, y
assert(isinstance(x, str) and isinstance(y, str))
def __repr__(self):
return f'Point({self.x}, {self.y})'
def __str__(self):
return f'({self.x}, {self.y})'
测试:
p = Point(2, 5)
p
Point(2, 5)
q = Point(2.1, 5.5)
Traceback (most recent call last):
File “<pyshell#25>”, line 1, in
q = Point(2.1, 5.5)
File “<pyshell#22>”, line 4, in __init__
assert(isinstance(x, int) and isinstance(y, int))
AssertionError
魔法方法
也称为特殊方法或双下划线方法,是python语言中的一种特殊方法,用于在类中实现一些特殊的功能。这些方法的名称始终以双下划线开头和结尾,比如上面点类定义时用到 __init__,__repr__,__str__。重载运算符时,我们就是靠魔法方法来重新定义运算符的,例如 __add__,__sub__,__mul__,__truediv__ 分别对应加减乘除四则运算。
在重载运算符前,再来学习几个其他类型的魔法方法:
__getitem__
__getitem__ 方法用于获取下标对应的值。
__setitem__
__setitem__ 方法用于设置下标对应的值。
定义完后,点类可以用下标0,1或者-2,-1来取值,和元组、列表等一样:obj[0], obj[1]。
class Point:
def __init__(self, x=0, y=0):
self.x, self.y = x, y
def __repr__(self):
return f'Point({self.x}, {self.y})'
def __getitem__(self, index):
if index in range(-2,2):
return self.y if index in (1,-1) else self.x
raise IndexError("Index out of range")
def __setitem__(self, index, value):
if index in (0, -2):
self.x = value
elif index in (1, -1):
self.y = value
else:
raise IndexError("Index out of range.")
测试:
a = Point(1,2)
a[0], a[1]
(1, 2)
a[-1], a[-2]
(2, 1)
a[0] = 5
a
Point(5, 2)
a[1] = 3
a
Point(5, 3)
[i for i in a]
[5, 3]
x, y = a
x
5
y
3
b = iter(a)
next(b)
5
next(b)
3
next(b)
Traceback (most recent call last):
File “<pyshell#67>”, line 1, in
next(b)
StopIteration
__iter__
__next__
共同定义一个对象的迭代行为,迭代器必须实现__iter__()方法,该方法返回迭代器自身,或者返回一个新的迭代器对象。__next__()方法返回迭代器的下一个元素。
class Point:
def __init__(self, x=0, y=0):
self.x, self.y = x, y
self.index = 0
def __repr__(self):
return f'Point({self.x}, {self.y})'
def __iter__(self):
self.index = 0
return self
def __next__(self):
if self.index < 2:
result = self.y if self.index else self.x
self.index += 1
return result
else:
raise StopIteration
测试:
a = Point(5, 3)
x, y = a
x, y
(5, 3)
next(a)
Traceback (most recent call last):
File “<pyshell#115>”, line 1, in
next(a)
File “<pyshell#111>”, line 16, in __next__
raise StopIteration
StopIteration
a = Point(5, 3)
next(a)
5
next(a)
3
a
Point(5, 3)
a.x
5
next(a)
Traceback (most recent call last):
File “<pyshell#121>”, line 1, in
next(a)
File “<pyshell#111>”, line 16, in __next__
raise StopIteration
StopIteration
a[0]
Traceback (most recent call last):
File “<pyshell#122>”, line 1, in
a[0]
TypeError: ‘Point’ object is not subscriptable
对于点类说,可迭代魔法方法完全可弃用;因为使用__getitem__方法和iter()函数已有此功能。
__len__
求长度的方法,原义就是计算可迭代对象元素的个数;点类的长度就是2。
def __len__(self):
return 2
__neg__
求相反数的方法,也就是单目的**“ - ”**符号;重载为横纵坐标都取相反数。
def __neg__(self):
return Point(-self.x, -self.y)
__pos__
这是单目的**“ + ”**符号,一般无需重新定义;但是我们还是把它重载成穿过点的横纵两条直线上所有的整数点坐