如何更好地理解Python迭代器和生成器

作者&投稿:止具 (若有异议请与网页底部的电邮联系)
如何更好地理解python的迭代器和生成器 知乎~

当一个log文件有很多行(maybe几万行)的时候,用cat ,你就会发现屏幕不停的刷刷刷,你怎么看?
so,这时候你需要用more来一页一页的阅读。
同样的道理,当文件被读入到内存时候,如果数据太大,会导致内存被占用过多。这时候需要一个像more的功能一次读取一点,这个就是迭代的功能。
那么怎么样才能有这样的功能存在呢?这就是生成器的作用。让cat aa.txt通过生成器变成more aa.txt的效果。

iamlaosong文
我们在用for
...
in
...语句循环时,in后面跟随的对象要求是可迭代对象,即可以直接作用于for循环的对象统称为可迭代对象(iterable),如list、tuple、dict、set、str等。
可迭代对象是实现了__iter__()方法的对象,而迭代器(iterator)则是实现了__iter__()和__next__()方法的对象,可以显示地获取下一个元素。这种可以被next调用并不断返回下一个值的对象称为迭代器。迭代器一定是可迭代对象,反过来则不一定成立。用iter()函数可以把list、dict、str等iterable变成iterator,例如:
bb=[x
for
x
in
range(10)]
cc=iter(bb)
cc.next()
循环变量的值其实可以看着是一次次用next取值的过程,每取一个值,做一次处理。list等对象用于循环实际上可以看着是用iter()方法产生一个迭代器,然后循环取值。
生成器(generator)就是一个能返回迭代器的函数,其实就是定义一个迭代算法,可以理解为一个特殊的迭代器。调用这个函数就得到一个迭代器,生成器中的yield相当于一个断点,执行到此返回一个值后暂停,从而实现next取值。

  迭代器和生成器都是Python中特有的概念,迭代器可以看作是一个特殊的对象,每次调用该对象时会返回自身的下一个元素,从实现上来看,一个可迭代的对象必须是定义了__iter__()方法的对象,而一个迭代器必须是定义了__iter__()方法和next()方法的对象。生成器的概念要比迭代器稍显复杂,因为生成器是能够返回一个迭代器的函数,其最大的作用是将输入对象返回为一个迭代器。Python中使用了迭代的概念,是因为当需要循环遍历一个较大的对象时,传统的内存载入方式会消耗大量的内存,不如需要时读取一个元素的方式更为经济快捷。
迭代器
  迭代器(iterator)是一种对象,它能够用来遍历标准模板库容器中的部分或全部元素,每个迭代器对象代表容器中的确定的地址。迭代器修改了常规指针的接口,所谓迭代器是一种概念上的抽象:那些行为上像迭代器的东西都可以叫做迭代器。然而迭代器有很多不同的能力,它可以把抽象容器和通用算法有机的统一起来。
  迭代器提供一些基本操作符:*、++、==、!=、=。这些操作和C/C++“操作array元素”时的指针接口一致。不同之处在于,迭代器是个所谓的复杂的指针,具有遍历复杂数据结构的能力。其下层运行机制取决于其所遍历的数据结构。因此,每一种容器型别都必须提供自己的迭代器。事实上每一种容器都将其迭代器以嵌套的方式定义于内部。因此各种迭代器的接口相同,型号却不同。这直接导出了泛型程序设计的概念:所有操作行为都使用相同接口,虽然它们的型别不同。
  迭代器使开发人员能够在类或结构中支持foreach迭代,而不必整个实现IEnumerable或者IEnumerator接口。只需提供一个迭代器,即可遍历类中的数据结构。当编译器检测到迭代器时,将自动生成IEnumerable接口或者IEnumerator接口的Current,MoveNext和Dispose方法。
生成器
  生成器是一次生成一个值的特殊类型函数。可以将其视为可恢复函数。调用该函数将返回一个可用于生成连续 x 值的生成器【Generator】
  简单的说就是在函数的执行过程中,yield语句会把你需要的值返回给调用生成器的地方,然后退出函数,下一次调用生成器函数的时候又从上次中断的地方开始执行,而生成器内的所有变量参数都会被保存下来供下一次使用。

我来举例:
当一个txt文件有几万行的时候,你是用cat ,会发现屏幕不停的刷不停的刷,影响你正常阅读。
这时候你需要使用more来一页一页阅读。
同样的道理,当文件被读入到内存时候,如果数据太大,会导致内存被占用过多。这时候需要一个向more的功能一次读取一点,这个就是迭代器的功能。

那么怎么样才能有这样的功能存在呢?这就是生成器的作用。让cat aa.txt通过生成器变成more aa.txt的效果。

在Python中,有些名称会在前后加上两个下划线,这种拼写表示名字有特殊含义。所以绝不要在自己的程序中使用这种名字。
1. __init__方法
Python 类中有默认的构造函数__init__我们可以覆盖它来试试。如下:
class FooBar:
def __init__(self): self.somevar=42 f=FooBar() print f.somevar
我们修改一下如下:
class FooBar:
def __init__(self,value=42): self.somevar=value f=FooBar("what's this?")
print f.somevar
输出如下:
what's this?

2. 重写方法
如果一个方法在B类的一个实例中被调用,但在B类中没有找到方法,那么就会在超类A里面找。 如下所示:
class A:
def hello(self):
print "hello ,I.m A" class B(A): pass

a=A() b=B() a.hello() b.hello()
输出如下:
hello ,I.m A hello ,I.m A
B类没有定义自己的方法hello调用的是父类的hello方法。 如果进行重写这个方法,如下:
class A:
def hello(self):
print "hello ,I.m A" class B(A): pass
def hello(self): print "Hello,I'm B" a=A() b=B() a.hello() b.hello()
输出如下:
hello ,I.m A Hello,I'm B

3. 使用Super函数
我看来看下个例子如下:
class Bird:
def __init__(self): self.hungry=True def eat(self): if self.hungry: print 'Aaah...' self.hungry=False else:
print "No,thansk"
class SongBird(Bird): def __init__(self): self.sound='Squawk!'

def sing(self): print self.sound
sb=SongBird() sb.sing() sb.eat()
运行如下:
Squawk!
Traceback (most recent call last):
AttributeError: SongBird instance has no attribute 'hungry'
没有hungry属性。
没有得到父类的属性,需要用到Super函数,处理后如下:
from _pyio import __metaclass__ __metaclass__=type class Bird:
def __init__(self): self.hungry=True def eat(self): if self.hungry: print 'Aaah...' self.hungry=False else:
print "No,thansk"
class SongBird(Bird): def __init__(self): # Bird.__init__(self)
super(SongBird,self).__init__() self.sound='Squawk!' def sing(self): print self.sound
sb=SongBird() sb.sing() sb.eat()

运行如下:
Squawk! Aaah...

   迭代器是访问集合元素的一种方式。迭代器对象从集合的第一个元素开始访问,知道所有的元素被访问完结束。迭代器只能往前不会后退,不过这也没什么,因为人们很少在迭代途中往后退。

  使用迭代器的优点

  对于原生支持随机访问的数据结构(如tuple、list),迭代器和经典for循环的索引访问相比并无优势,反而丢失了索引值(可以使用内建函数enumerate()找回这个索引值)。但对于无法随机访问的数据结构(比如set)而言,迭代器是唯一的访问元素的方式。

  另外,迭代器的一大优点是不要求事先准备好整个迭代过程中所有的元素。迭代器仅仅在迭代到某个元素时才计算该元素,而在这之前或之后,元素可以不存在或者被销毁。这个特点使得它特别适合用于遍历一些巨大的或是无限的集合,比如几个G的文件,或是斐波那契数列等等。

  迭代器更大的功劳是提供了一个统一的访问集合的接口,只要定义了__iter__()方法对象,就可以使用迭代器访问。

  迭代器有两个基本的方法

  • next方法:返回迭代器的下一个元素

  • __iter__方法:返回迭代器对象本身

  简单地讲,yield 的作用就是把一个函数变成一个 generator,带有 yield 的函数不是一个普通函数,Python 解释器会将其视为一个 generator,调用 fab(5) 不会执行fab 函数,而是返回一个 iterable 对象!在 for 循环执行时,每次循环都会执行 fab 函数内部的代码,执行到 yield b 时,fab 函数就返回一个迭代值,下次迭代时,代码从 yield b 的下一条语句继续执行,而函数的本地变量看起来和上次中断执行前是完全一样的,于是函数继续执行,直到再次遇到 yield。看起来就好像一个函数在正常执行的过程中被 yield 中断了数次,每次中断都会通过 yield 返回当前的迭代值。



对于原生支持随机访问的数据结构(如tuple、list),迭代器和经典for循环的索引访问相比并无优势,反而丢失了索引值(可以使用内建函数enumerate()找回这个索引值)。但对于无法随机访问的数据结构(比如set)而言,迭代器是唯一的访问元素的方式。

另外,迭代器的一大优点是不要求事先准备好整个迭代过程中所有的元素。迭代器仅仅在迭代到某个元素时才计算该元素,而在这之前或之后,元素可以不存在或者被销毁。这个特点使得它特别适合用于遍历一些巨大的或是无限的集合,比如几个G的文件,或是斐波那契数列等等。

迭代器更大的功劳是提供了一个统一的访问集合的接口,只要定义了__iter__()方法对象,就可以使用迭代器访问。


描写春天的诗
等闲识得东风面,万紫千红总是春。《忆江南·江南好》【唐】白居易 江南好,风景旧曾谙。日出江花红胜火,春来江水绿如蓝。能不忆江南?江南忆,最忆是杭州。山寺月中寻桂子,郡亭枕上看潮头。何日更重游?江南忆,其次忆吴宫。吴酒一杯春竹叶,吴娃双舞醉芙蓉。早晚复相逢?

形容新叶的诗句有哪些
回答者:h2pyt 时间:2010-03-27 10:18:00 叶上初阳干宿雨,水面清圆,一一风荷举。江南可采莲,莲叶何田田。 慈姑叶烂别西湾,莲子花开不见还。莫听穿林打叶声,何妨吟啸且徐行。 停车坐爱枫林晚,霜叶红于二月花。荷叶罗裙一色裁,芙蓉向脸两边开。 一点残红影下,青山绿水白草红叶黄花。碧云天,黄叶地,秋色连波...

潍城区15860374528: 如何更好地理解Python迭代器和生成器 -
巫衫苯唑: 更好的理解python的迭代器和生成器,可以打个比方 ,赌场发牌的荷官算是一个不错的比喻.本来你需要自己去处理一堆牌(一个 collection),现在你有了这个对象,只要不断问他要“下一张”,他要是有自然会给你,没有就结束(StopIteration).

潍城区15860374528: Python中生成器和迭代器的区别 -
巫衫苯唑: 更好的理解python的迭代器和生成器,可以打个比方 ,赌场发牌的荷官算是一个不错的比喻. 本来你需要自己去处理一堆牌(一个 collection),现在你有了这个对象,只要不断问他要“下一张”,他要是有自然会给你,没有就结束(StopIteration).

潍城区15860374528: python 可迭代对象和迭代器的区别 -
巫衫苯唑: Iamlaosong文 我们在用for ... in ...语句循环时,in后面跟随的对象要求是可迭代对象,即可以直接作用于for循环的对象统称为可迭代对象(Iterable),如list、tuple、dict、set、str等. 可迭代对象是实现了__iter__()方法的对象,而迭代器(...

潍城区15860374528: python生成器和迭代器的区别 -
巫衫苯唑: 先说迭代器,对于string、list、dict、tuple等这类容器对象,使用for循环遍历是很方便的.在后台for语句对容器对象调用iter()函数,iter()是python的内置函数.iter()会返回一个定义了next()方法的迭代器对象

潍城区15860374528: python中迭代器和生成器的区别 -
巫衫苯唑: 对于list、string、tuple、dict等这些容器对象,使用for循环遍历是很方便的.在后台for语句对容器对象调用iter()函数.iter()是Python内置函数.iter()会返回一个定义了next()方法的迭代器对象,它在容器中逐个访问容器内的元素.next()也是python内置函数.在没有后续元素时,next()会抛出一个StopIteration异常,通知for语句循环结束.

潍城区15860374528: Python中迭代器和生成器的区别与联系 -
巫衫苯唑: 用代码说明下 def miter(): return list(range(10)) def myield(): for i in range(10): yield i print(miter()) print(myield())输出是 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]<generator object myield at 0x000002A0118740F8>不知道,你发现什么东西没?迭代器,是直接返回...

潍城区15860374528: python中的迭代器有什么用 -
巫衫苯唑: 什么是迭代 可以直接作用于for循环的对象统称为可迭代对象(Iterable).可以被next()函数调用并不断返回下一个值的对象称为迭代器(Iterator).所有的Iterable均可以通过内置函数iter()来转变为Iterator.对迭代器来讲,有一个__next ...

潍城区15860374528: python 迭代器和生成器的区别 -
巫衫苯唑: Num01–>迭代器 定义: 对于list、string、tuple、dict等这些容器对象,使用for循环遍历是很方便的.在后台for语句对容器对象调用iter()函数.iter()是python内置函数. iter()函数会返回一个定义了next()方法的迭代器对象,它在容器...

潍城区15860374528: [python]关于python的迭代器和列表推导的问题 -
巫衫苯唑: 这句相当于 count = 0 a = [] while True: count += 1 if count 显然是个死循环 问题出在你的迭代类里没有终止条件 class numCounter: 'this is a class to simulate a counter' def __init__(self,max=10): self.max = max self.count=0 def __next__(self): self....

潍城区15860374528: python的迭代器为什么一定要实现 -
巫衫苯唑: 这是个和多态有关的问题,Python中关于迭代有两个概念,第一个是Iterable,第二个是Iterator,协议规定Iterable的__iter__方法会返回一个Iterator, Iterator的__next__方法(Python 2里是next)会返回下一个迭代对象,如果迭代结束则抛出...

本站内容来自于网友发表,不代表本站立场,仅表示其个人看法,不对其真实性、正确性、有效性作任何的担保
相关事宜请发邮件给我们
© 星空见康网