&
- __getitem__
- __setitem__
方法被调用的应用场景
- __getitem__
对象实例根据索引值获取索引值对应的数据
- # indexer.py# 注:python如果没有特别说明表示都是3.x版本class Indexer:
- def __init__(self):
- print("call init ...")
- self.__data = [1,2,3] def __getitem__(self, index): # index为索引值
- print("call getitem index...") return self.__data[index]def test_index():
- # 取值
- for i in range(3):
- print(X[i]) # 等价于Indexer.__getitem__(X,i)if __name__ == '__main__':
- test_index()>>> python indexer.py
对象实例根据分片方式获取一组分片索引值对应的数据
- # slice.pyclass SliceObject:
- def __init__(self):
- print("call slice object init ...")
- self.__data = [1,2,3,4,5,6] def __getitem__(self, index): # index为索引值或者分片对象
- if isinstance(index, int):
- print('indexing', index) else: # 分片对象有start stop 以及step属性
- print('slicing', index.start, index.stop, index.step) return self.__data[index]def test_slice():
- X = SliceObject() # 分片取值
- print(X[0:2])
- print(X[:-1])
- print(X[1:])if __name__ == '__main__':
- test_slice()>>> python slice.py
迭代器调用并进行数据遍历
- # indexer.py def test_iterator():
- X = Indexer() for item in X:
- print(item)if __name__ == '__main__': # test_index()
- test_iterator()>>> python indexer.py
py2.x分片操作的内置方法,py3.x已经删除
- # slice.py class Slicer:
- """
- py2.x 分片
- """
- def __getitem__(self, index):
- print("call __getitem__ for index:%s" % str(index)) def __getslice__(self, i, j):
- print("call __getslice__ for start[%d] to end[%d]" % (i,j)) def __setslice__(self, i, j, seq):
- print("call __setslice__ for start[%d] to end[%d] with seq[%d]" % (i,j,seq)) def test_slicer():
- Slicer()[1]
- Slicer()[1:9]
- Slicer()[1:9:2]if __name__ == '__main__':
- test_slicer()>>> python slice.py
py3.x新增
内置方法,该方法表示返回一个实例对象的整数型,与索引切片没关系
- __index__
- # indexer.pyclass Indexing:
- """
- py3.x 新增的内置方法,但是该操作不是表示索引操作,而是为一个对象实例返回一个整型数值,并且用于转换为数值字符串的内置操作
- """
- def __index__(self):
- return 200 def test_indexing():
- X = Indexing() # 将对象转换为数值字符串,这里执行两个内置方法,__index__ 和 __str__
- print(hex(X))if __name__ == '__main__':
- test_indexing()>>> python indexer.py
对索引属性进行赋值操作
- __setitem__
- # indexer.pyclass Indexer:
- ...
- def __setitem__(self, index, value): # index恒为索引下标,value为值
- print("call setitem ...")
- print("key[%s]--value[%s]" % (index,value))
- self.__data.insert(index,value)def test_index():
- # 设置值
- X = Indexer()
- X[0] = 1 # 等价于Indexer.__setitem__(X,0,1)if __name__ == '__main__':
- test_index()>>> python indexer.py
3.迭代器对象:
&
- __iter__
- __next__
自定义迭代器
- # iterator.pyclass Squares:
- def __init__(self, start, stop):
- self.value = start - 1
- self.stop = stop def __iter__(self):
- # 生成迭代器对象
- print("call iter ...") return self def __next__(self):
- if self.value == self.stop: raise StopIteration
- print("call next for value:", end='')
- self.value += 1
- return self.value ** 2def test():
- X = Squares(1, 5) # 迭代器不支持使用索引
- X[1] # TypeError: 'Squares' object does not support indexingif __name__ == '__main__':
- test()>>> python iterator.py
使用循环迭代器
- # iterator.pydef test_for():
- # 循环使用迭代器
- for item in Squares(2, 9): # 调用Squares.__iter__,生成迭代器对象
- print(item) # 调用Squares.__next__>>> python iterator.py
逐个进行迭代
- # iterator.pydef test_single():
- # 逐个调用迭代器
- X = Squares(2, 9) # 显示将X转换为迭代器对象,条件是该对象有实现__iter__,只需调用一次
- I = iter(X) # Squares.__iter__
- print(next(I)) # 调用Squares.__next__
- print(next(I)) # 调用Squares.__next__if __name__ == '__main__':
- test_single()>>> python iterator.py
迭代器单次扫描
- # iterator.pydef single_scan():
- print("start single scan ....")
- X = Squares(1, 2) # 首次会执行__iter__对迭代器进行初始化,
- # 并且每次执行将调用__next__将数据返回并保存当前迭代器的状态,直至为不可迭代状态
- list1 = [n for n in X]
- print(list1) # 迭代器当前是不可迭代的状态,即list2是空列表
- list2 = [n for n in X] # now list2 is empty
- print(list2)
- print("end single scan ....")if __name__ == '__main__':
- single_scan()>>> python iterator.py
迭代器多次扫描
- # iterator.pydef mutil_scan():
- print("start mutil scan ... ") # 方式一:每次都是重新创建新的迭代器来进行迭代2.7没有next方法,不可用
- list1 = [n for n in Squares(1,2)]
- print(list1)
- list2 = [n for n in Squares(1, 2)]
- print(list2) # 方式二 转换为列表并用列表解析器来转换
- list_iter = list(Squares(1,2))
- list3 = [n for n in list_iter]
- print(list3)
- list4 = [n for n in list_iter]
- print(list4)
- print("end mutil scan ...")if __name__ == '__main__':
- mutil_scan()>>> python iterator.py
设计可多次迭代的类模板
中返回的迭代器应当新的迭代器对象,而不是self自身对象
- __iter__
- # iterator.pyclass MutilIterator:
- def __init__(self, wrapper):
- self.__wrapper = wrapper def __iter__(self):
- """
- 每次调用迭代器的时候就创建一个新的迭代器并返回
- """
- return DefineIterator(self.__wrapper)class DefineIterator:
- def __init__(self, wrapped):
- self.wrapped = wrapped
- self.offset = 0
- def __next__(self):
- if self.offset >= len(self.wrapped): raise StopIteration else:
- item = self.wrapped[self.offset]
- self.offset += 1
- return item # py2.x 没有next方法,兼容python2.x 和 python3.x
- next = __next__def test_mutil_object_iter():
- S = "abcd"
- # 索引遍历操作
- M = MutilIterator(S) for x in M: print("recreate iterator for y loop by creating M iterator ...") for y in M: # 第二次调用迭代器获取新的迭代器对象
- print(x+y,end = ",")
- print("") if __name__ == '__main__':
- test_mutil_object_iter()>>> python iterator.py
- # iterator.pyclass MixIterator:
- def __init__(self,start,stop):
- self.__start = start
- self.__stop = stop def __iter__(self):
- for index in range(self.__start,self.__stop+1): yield index**2 # 返回一个生成器对象,通过调用next()来显示值def test_mix_iterator():
- iterator = MixIterator(1,5) # 同一个对象可以迭代多次
- list1 = [index for index in iterator]
- list2 = [index for index in iterator]
- print(list1)
- print(list2)if __name__ == '__main__':
- test_mix_iterator()>>> python iterator.py
- # iterator.pyclass MutilIterator2:
- def __init__(self,wrapper):
- self.__wrapper = wrapper def __iter__(self):
- print("call iter ... ")
- offset = 0
- while offset < len(self.__wrapper):
- item = self.__wrapper[offset]
- offset+=1
- yield itemdef test_mutil2_iterator():
- S = "abcd"
- M = MutilIterator2(S) for x in M: # 执行__iter__方法
- for y in M: # 执行__iter__方法,进入方法的时候offset又变为初始化0
- print(x+y,end = ",")
- print()if __name__ == '__main__':
- test_mutil2_iterator()>>> python iterator.py
迭代器小结
来源: https://juejin.im/entry/59f3447b5188255a6a0d4b9d