# Python迭代和解析(4)：自定义迭代器

## 索引迭代方式

### 索引取值和分片取值

>>> L = [11,21,31,41]
>>> L[0]
11
>>> L[0:2]
[11, 21]


>>> L[0:2]
[11, 21]

>>> L[slice(0,2)]
[11, 21]


slice对象由slice()函数创建，它有3个参数：起始索引位、结束索引位、步进值。例如：

>>> slice(0,2)
slice(0, 2, None)


### __getitem__

>>> hasattr(list,"__getitem__")
True
>>> hasattr(tuple,"__getitem__")
True
>>> hasattr(dict,"__getitem__")
True
>>> hasattr(str,"__getitem__")
True


class cls:
def __getitem__(self, index):
print("getitem index", index)
return index * 2

>>> c = cls()
>>> c[1]
getitem index 1
2
>>> c[2]
getitem index 2
4
>>> c[3]
getitem index 3
6


### 分片和__getitem__

class cls:
def __init__(self,data):
self._data = data
def __getitem__(self,index):
print("getitem:",index)
return self._data[index]

>>> c = cls([1,2,3,4])
>>> c[1]
getitem: 1
2
>>> c[0:2]
getitem: slice(0, 2, None)
[1, 2]


### __setitem__和__delitem__

class cls:
def __init__(self,data):
self._data = data
def __getitem__(self,index):
print("in getitem")
return self._data[index]
def __setitem__(self,index,value):
print("in setitem")
self._data[index] = value
def __delitem__(self,index):
print("in delitem")
del self._data[index]
def __repr__(self):
return str(self._data)

>>> c = cls([11,22,33,44,55])
>>> c[1:3]
in getitem
[22, 33]
>>> c[1:3] = [222,333]
in setitem
>>> c
[11, 222, 333, 44, 55]
>>> del c[1:3]
in delitem


### __getitem__索引迭代

__getitem__重载了索引取值和分片操作，实际上它也能重载索引的迭代操作。以for为例，它会循环获取一个个的索引并向后偏移，直到超出索引边界抛出IndexError异常而停止。

class cls:
def __init__(self,data):
self._data = data
def __getitem__(self,index):
return self._data[index]
def __repr__(self):
return str(self._data)

>>> c1 = cls([11,22,33,44,55])
>>> I = iter(c1)
>>> next(I)
11
>>> 22 in I
True

>>> I=iter(c1)
>>> for i in I:print(i,end=" ")
...
11 22 33 44 55


## 可迭代对象：__iter__和__next__

class Squares:
def __init__(self, start, stop):  # 迭代起始、终止位
self.value = start
self.stop = stop

def __iter__(self):     # 返回自身的迭代器
return self

def __next__(self):     # 返回下一个元素
if self.value > self.stop:   # 结尾时抛出异常
raise (StopIteration)
item = self.value**2
self.value += 1
return item

if __name__ == "__main__":
for i in Squares(1, 5):
print(i, end=" ")

s = Squares(1,5)
print()
print(9 in s)


1 4 9 16 25
True


>>> s = Squares(1,5)
>>> I1 = iter(s)   # I1和I2迭代的是同一个对象
>>> I2 = iter(s)
>>> next(I1)
1
>>> next(I2)   # 继续从前面的位置迭代
4
>>> next(I1)
9


## 自定义多迭代类型

# 返回多个独立的可迭代对象
class MultiIterator:
def __init__(self, wrapped):
self.wrapped = wrapped   # 封装将被迭代的对象

def __iter__(self):
return Next(self.wrapped) # 返回独立的可迭代对象

# 自身的迭代器
class Next:
def __init__(self, wrapped):
self.wrapped = wrapped
self.offset = 0

def __iter__(self):
return self

def __next__(self):   # 返回下一个元素
if self.offset >= len(self.wrapped):
raise (StopIteration)
else:
item = self.wrapped[self.offset]
self.offset += 1
return item    # 返回指定索引位置处的元素

if __name__ == "__main__":
string = "abc"
s = MultiIterator(string)
for x in s:
for y in s:
print(x + y, end=" ")


posted @ 2019-01-13 17:10  骏马金龙  阅读(3079)  评论(0编辑  收藏  举报