博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Python 迭代器 & __iter__方法
阅读量:5367 次
发布时间:2019-06-15

本文共 2283 字,大约阅读时间需要 7 分钟。

看到类似__slots__这种形如__xxx__的变量或者函数名就要注意,这些在Python中是有特殊用途的。

__iter__

如果一个类想被用于for ... in循环,类似list或tuple那样,就必须实现一个__iter__()方法,该方法返回一个迭代对象,然后,Python的for循环就会不断调用该迭代对象的next()方法拿到循环的下一个值,直到遇到StopIteration错误时退出循环。

迭代器就是重复地做一些事情,可以简单的理解为循环,在python中实现了__iter__方法的对象是可迭代的,实现了next()方法的对象是迭代器,这样说起来有点拗口,实际上要想让一个迭代器工作,至少要实现__iter__方法和next方法。很多时候使用迭代器完成的工作使用列表也可以完成,但是如果有很多值列表就会占用太多的内存,而且使用迭代器也让我们的程序更加通用、优雅、pythonic。

我们以斐波那契数列为例,写一个Fib类,可以作用于for循环:

class Fib(object):    def __init__(self):        self.a, self.b = 0, 1 # 初始化两个计数器a,b    def __iter__(self):        return self # 实例本身就是迭代对象,故返回自己    def next(self):        self.a, self.b = self.b, self.a + self.b # 计算下一个值        if self.a > 100000: # 退出循环的条件            raise StopIteration();        return self.a # 返回下一个值
for n in Fib():...     print n...11235...

__getitem__

Fib实例虽然能作用于for循环,看起来和list有点像,但是,把它当成list来使用还是不行,比如,取第5个元素:

Fib()[5]Traceback (most recent call last):  File "
", line 1, in
TypeError: 'Fib' object does not support indexing

要表现得像list那样按照下标取出元素,需要实现__getitem__()方法:

class Fib(object):    def __getitem__(self, n):        a, b = 1, 1        for x in range(n):            a, b = b, a + b        return a>>> f = Fib()>>> f[0]1>>> f[1]1>>> f[2]2>>> f[3]

但是list有个神奇的切片方法:

>>> range(100)[5:10][5, 6, 7, 8, 9]#对于Fib却报错。原因是__getitem__()传入的参数可能是一个int,也可能是一个切片对象slice,所以要做判断:class Fib(object):    def __getitem__(self, n):        if isinstance(n, int):            a, b = 1, 1            for x in range(n):                a, b = b, a + b            return a        if isinstance(n, slice):            start = n.start            stop = n.stop            a, b = 1, 1            L = []            for x in range(stop):                if x >= start:                    L.append(a)                a, b = b, a + b            return L#现在试试Fib的切片:>>> f = Fib()>>> f[0:5][1, 1, 2, 3, 5]>>> f[:10][1, 1, 2, 3, 5, 8, 13, 21, 34, 55]#但是没有对step参数作处理:>>> f[:10:2][1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]

也没有对负数作处理,所以,要正确实现一个__getitem__()还是有很多工作要做的。

 

此外,如果把对象看成dict,__getitem__()的参数也可能是一个可以作key的object,例如str。

与之对应的是__setitem__()方法,把对象视作list或dict来对集合赋值。最后,还有一个__delitem__()方法,用于删除某个元素。

总之,通过上面的方法,我们自己定义的类表现得和Python自带的list、tuple、dict没什么区别,这完全归功于动态语言的“鸭子类型”,不需要强制继承某个接口。

转载于:https://www.cnblogs.com/kamil/p/5206709.html

你可能感兴趣的文章
Java作业(六)
查看>>
微信小程序播放背景音乐
查看>>
学号 20175223 《Java程序设计》第 5 周学习总结
查看>>
es6的find和findIndex方法
查看>>
Java中的interface接口
查看>>
常见linux命令释义(第五天)——shell变量学习
查看>>
Dell服务器R320在Centos6.5系统上安装MegaCli管理主板集成磁盘阵列卡
查看>>
PHP实现html字符实体转汉字
查看>>
洛谷 P1203 [USACO1.1]坏掉的项链Broken Necklace
查看>>
MongoDB之bson的介绍
查看>>
.NET Core IdentityServer4实战 第三章-使用EntityFramework Core进行持久化配置
查看>>
sql面试题一 学生成绩
查看>>
【深度学习大讲堂】首期第一讲:人工智能的ABCDE 第一部分:从人工智能和计算机视觉说起...
查看>>
2016/2/21 JavaScript简介
查看>>
关于Javascript调用asp.Net后台代码
查看>>
springcloud-06-feign的使用
查看>>
代码经验总结(未完)
查看>>
BZOJ1925: [Sdoi2010]地精部落
查看>>
ReportViewer实例教程(转载)
查看>>
php中文文件is_file检验失败(编码问题)
查看>>