本篇的主角正是“点”,今天要用运算符重载来,把它玩出“点”花样来!那什么是运算符重载呢?
运算符重载
运算符重载是面向对象编程中的一个概念,它允许程序员为自定义类型(如类或结构体)定义特定的运算符行为,使得这些类的实例可以使用语言中预定义的运算符。在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__
这是单目的**“ + ”**符号,一般无需重新定义;但是我们还是把它重载成穿过点的横纵两条直线上所有的整数点坐标&