Python迭代和解析(4):自定义迭代器
解析、迭代和生成系列文章:https://www.cnblogs.com/f-ck-need-u/p/9832640.html
本文介绍如何自定义迭代器,涉及到类的运算符重载,包括__getitem__
的索引迭代,以及__iter__
、__next__
和__contains__
,如果不了解这些知识可跳过本文。
索引迭代方式
索引取值和分片取值
元组、列表、字典、集合、字符串都支持索引取值操作和分片操作。
>>> L = [11,21,31,41]
>>> L[0]
11
>>> L[0:2]
[11, 21]
分片操作实际上将一个slice对象当作索引位传递给序列,然后以索引取值的方式取得所需元素。
>>> L[0:2]
[11, 21]
>>> L[slice(0,2)]
[11, 21]
slice对象由slice()函数创建,它有3个参数:起始索引位、结束索引位、步进值。例如:
>>> slice(0,2)
slice(0, 2, None)
__getitem__
列表、元组等序列之所以可以索引取值、分片取值,是因为它们实现了__getitem__
方法。
例如:
>>> hasattr(list,"__getitem__")
True
>>> hasattr(tuple,"__getitem__")
True
>>> hasattr(dict,"__getitem__")
True
>>> hasattr(str,"__getitem__")
True
如果自定义类并实现__getitem__
方法,它们会重载索引取值:
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__
中没有编写索引取值的方式,也就不支持传递slice对象来进行分片取值。
分片和__getitem__
如果想要__getitem__
支持分片取值,需要在__getitem__
中使用索引取值的方式,以便支持slice对象作为索引。
下面是一个简单的支持分片操作的自定义类:
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__
如果想要索引或者分片赋值,那么会调用__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异常而停止。
此外,__getitem__
重载使得它可以被迭代,也就是它通过数值索引的方式让这个对象变成可迭代对象,所有迭代工具(比如zip/map/for/in)都可以对这个对象进行迭代操作。
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__
定以了__getitem__
的类是可迭代的类型,是通过数值索引的方式进行迭代的,但这是退而求其次的行为,更好的方式是定义__iter__
方法,使用迭代协议进行迭代。当同时定义了__iter__
和__getitem__
的时候,iter()函数优先选择__iter__
,只有在__iter__
不存在的时候才会选择__getitem__
。
例如:
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
因为上面的类中同时定义了__iter__
和__next__
,且__iter__
返回的是自身,所以这个类型的每个迭代对象都是单迭代的。
>>> s = Squares(1,5)
>>> I1 = iter(s) # I1和I2迭代的是同一个对象
>>> I2 = iter(s)
>>> next(I1)
1
>>> next(I2) # 继续从前面的位置迭代
4
>>> next(I1)
9
自定义多迭代类型
要定义多迭代的类型,要求__iter__
返回一个新的迭代对象,而不是self自身,也就是说不要返回自身的迭代器。
例如:
# 返回多个独立的可迭代对象
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=" ")
每个for迭代工具都会先调用iter()来获取可迭代对象,然后调用next()获取下一个元素。而这里的iter()会调用MultiIterator的__iter__
来获取可迭代对象,而MultiIterator
所返回的可迭代对象是相互独立的Next对象,因此for x in x
和for y in s
所迭代的是不同迭代对象,它们都有记录着自己的迭代位置信息。
Python迭代和解析(4):自定义迭代器的更多相关文章
- Python迭代和解析(2):迭代初探
解析.迭代和生成系列文章:https://www.cnblogs.com/f-ck-need-u/p/9832640.html 在Python中支持两种循环格式:while和for.这两种循环的类型不 ...
- Python迭代和解析(1):列表解析
解析.迭代和生成系列文章:https://www.cnblogs.com/f-ck-need-u/p/9832640.html Python中的解析 Python支持各种解析(comprehensio ...
- Python迭代和解析(5):搞懂生成器和yield机制
解析.迭代和生成系列文章:https://www.cnblogs.com/f-ck-need-u/p/9832640.html 何为生成器 生成器的wiki页:https://en.wikipedia ...
- python迭代和解析(3):range、map、zip、filter和reduce函数
解析.迭代和生成系列文章:https://www.cnblogs.com/f-ck-need-u/p/9832640.html range range()是一个内置函数,它返回一个数字序列,功能和Li ...
- Python基础(冒泡、生成器、迭代器、列表与字典解析)
一.冒泡算法 冒泡算法,给定一组数据,从大到小排序或者从小到大排序,就像气泡一样 原理: 相邻的两个对象相比,大的放到后面,交换位置 交换位置通过a,b=b,a来实现 1.我们可以通过for循环来根 ...
- 完全理解 Python 迭代对象、迭代器、生成器
完全理解 Python 迭代对象.迭代器.生成器 2017/05/29 · 基础知识 · 9 评论 · 可迭代对象, 生成器, 迭代器 分享到: 原文出处: liuzhijun 本文源自RQ作者 ...
- Python 学习 第六篇:迭代和解析
Python中的迭代是指按照元素的顺序逐个调用的过程,迭代概念包括:迭代协议.可迭代对象和迭代器三个概念. 迭代协议是指有__next__()函数的对象会前进到下一个结果,而到达系列的末尾时,则会引发 ...
- python函数:叠加装饰器、迭代器、自定义迭代器、生成式
一.叠加多个装饰器二.迭代器三.自定义迭代器四.xxx生成式 一.叠加多个装饰器 # 加载装饰器就是将原函数名偷梁换柱成了装饰器最内层那个wrapper函数 # 在加载完毕后,调用原函数其实就是在调用 ...
- Python 3.x自定义迭代器对象
Python 3.x与Python 2.x之间存在着较多的语法细节差异.今天在看Python核心编程的时候,说到了自定义迭代器对象.于是动手将源码打了一遍,原书代码如下: class AnyIter( ...
随机推荐
- vue 源码学习二 实例初始化和挂载过程
vue 入口 从vue的构建过程可以知道,web环境下,入口文件在 src/platforms/web/entry-runtime-with-compiler.js(以Runtime + Compil ...
- mybatis3源码阅读之SqlSessionFactoryBuilder
/** 构造器,根据配置或者代码生成SqlSessionFactory,采用分布构建的Builder模式 /* public class SqlSessionFactoryBuilder { /** ...
- cmd 创建用户,并授权管理员权限就可以远程登陆了
创建账号 net user 用户名 密码 /add //注意空格 授权管理员权限 net localgroup Administrators 用户名 /add // ...
- 将博客搬至CSDN http://blog.csdn.net/yi_xianyong
将博客搬至CSDN http://blog.csdn.net/yi_xianyong
- H5 和移动端 WebView 缓存机制解析与实战
本文来自于腾讯Bugly公众号(weixinBugly),未经作者同意,请勿转载,原文地址:https://mp.weixin.qq.com/s/qHm_dJBhVbv0pJs8Crp77w 作者:叶 ...
- springboot加ES实现全局检索
ElasticSearch是一个基于Lucene的搜索服务器.它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口.Elasticsearch是用Java开发的,并作为Apach ...
- phpcms2008远程代码执行漏洞
phpcms2008远程代码执行漏洞 描述: 近日,互联网爆出PHPCMS2008代码注入漏洞(CVE-2018-19127).攻击者利用该漏洞,可在未授权的情况下实现对网站文件的写入.该漏洞危害程度 ...
- 推荐 | Vue 入门&进阶路线
今儿跟大家聊聊 Vue . 不得不承认, Vue 越来越受欢迎了.对比 Angular 和 React,虽然三者都是非常优秀的前端框架,但从 GitHub 趋势看,Vue 已经排在第一位,达到了13万 ...
- [Swift]LeetCode268. 缺失数字 | Missing Number
Given an array containing n distinct numbers taken from 0, 1, 2, ..., n, find the one that is missin ...
- [Swift]LeetCode818. 赛车 | Race Car
Your car starts at position 0 and speed +1 on an infinite number line. (Your car can go into negati ...