基础知识
运算符重载让类拦截常规的Python运算。
类可重载所有Python表达式运算符。
类也可以重载打印、函数调用、属性点号运算等内置运算。
重载使类实例的行为像内置类型。
重载是通过提供特殊名称的类方法来实现的。
构造函数和表达式:__init__和__sub__
__init__:构造函数
__sub__:捕捉减法表达式
例如number.py如下:
class Number:
def __init__(self, start):
self.data = start
def __sub__(self, other):
return Number(self.data - other)
测试两者:
from number import Number
X = Number(5)
Y = X - 2
print(Y.data)
运行结果:3
常见的运算符重载方法
索引和分片:__getitem__和__setitem__
对于实例的索引运算,会自动调用__getitem__。例如X[i]这样的索引运算中,把X作为第一个参数传递,并且方括号内的索引值传给第二个参数。
实例:
class Indexer:
def __getitem__(self, item):
return item ** 2
X = Indexer()
print(X[2])
运行结果:4
拦截分片
分片表达式也用__getitem__
# __getitem__用于索引分片
class Indexer:
data = [5,6,7,8,9]
def __getitem__(self, item):
print('getitem:', item)
return self.data[item]
X = Indexer()
print(X[2])
print(X[2:4])
运行结果:
索引迭代:__getitem__
__getitem__也可以是Python中一种重载迭代的方式,如果定义了这个方法,for循环每次循环时都会调用类的__getitem__。
class stepper:
def __getitem__(self, item):
print("__getitem__ -> item:%s " % item)
return self.data[item]
X = stepper()
X.data = 'Spam'
print(X[1])
print('*********')
for item in X:
print(item)
运行结果:
任何支持for循环的类也会自动支持Python所有迭代环境,例如,成员关系测试in、列表解析、内置函数map、列表和元组赋值运算以及类型构造方法也会自动调用__getitem__(如果定义了的话)。
print('p' in X)
print(c for c in X)
print(list(map(str.upper,X)))
运行结果:
迭代器对象:__iter__和__next__
应该优先使用__iter__,它能够比__getitem__更好地支持一般的迭代环境
用户定义的迭代器
实例:
class Squares:
def __init__(self, start, stop):
self.value = start - 1
self.stop = stop
def __iter__(self):
return self
def __next__(self):
if self.value == self.stop:
raise StopIteration
self.value += 1
return self.value ** 2
for i in Squares(1,5):
print(i, end=' ')
运行结果:1 4 9 16 25
和__getitem__不同:__iter__只循环一次,而不是循环多次(每次新的循环,都得创建一个新的迭代器对象)
X = Squares(1,5)
print([n for n in X])
print([n for n in X])
print([n for n in Squares(1,5)])
运行结果:
有多个迭代器的对象