迭代器和生成器入门

Python 迭代器生成器

迭代器、生成器这些概念名称真是让人头大,其实它们的原理特别简单、深刻。

可迭代对象(iterable)

在讲迭代器和生成器之前,必须要讲的一个概念就是可迭代对象。

可迭代对象之前需要聊一下Python中的那些内置数据结构--列表、字典、集合、元组等,这些数据结构就像一个装有内置数据的容器。

这里可以这么想--把数据想象成苹果,把列表、字典、集合、元组等想像成装苹果的袋子、盒子、篮子、筐子等装苹果的容器。

我们都能从这些容器中一个一个把所有苹果拿出来,这就像是我们经常使用 for循环,从列表、字典、集合、元组等中依次取出所有数据的操作。

就像袋子、盒子、篮子、筐子这些物品不能决定我们如何从它们内部拿出苹果一样,列表、字典、集合、元组等也不能决定我们如何从它们内部拿出数据。

是使用它们的人定义了一些规矩--可以一次拿一个出来,直到东西被拿完为止。而这个规矩就是可迭代协议。

符合可迭代协议的就是可迭代对象。列表、字典、集合、元组等这些我们常见的数据结构都是可迭代对象。

但是还有一些也满足我们那个规矩的比如:我们可以依次从一个 打开的文件句柄中拿出一行内容,我们还可以依次从一个 socket拿出指定长度的数据。 这些都是可迭代对象,因为它们都符合我们之前定下的那个规矩。

那如何证明它们都遵守了我们定下的规矩呢? 有一个条件,只要它们实现了 __iter__方法的话,我们就认为它们是符合我们的规矩的。 我们就可以认为它们是可迭代对象。

迭代器(iterator)

我们上面说完了可迭代对象和它必须有的一个方法( __iter__)。

那迭代器是什么呢?

我们只要执行可迭代对象的 __iter__方法就能得到一个 迭代器。 并且这个迭代器会有一个 __next__方法。

在这里我们就拿Python中的列表来举例:

  1. >>> l = [1, 2, 3]  # 这里是一个列表
  2. >>> i = l.__iter__()  # 调用__iter__方法
  3. >>> i  # 得到一个迭代器
  4. <list_iterator object at 0x104db2a90>

那迭代器如何使用呢?

我们只要执行迭代器的 __next__方法就可以了。想象一下我们从一个袋子里一次拿出一个苹果来,直到最后我们在袋子底儿摸了一圈发现没有苹果了。

  1. >>> i.__next__()  # 拿一个数据
  2. 1
  3. >>> i.__next__()  # 拿一个数据
  4. 2
  5. >>> i.__next__()  # 拿一个数据
  6. 3
  7. >>> i.__next__()  # 在迭代器 i 中再也拿不出数据了
  8. Traceback (most recent call last):
  9.  File "<stdin>", line 1, in <module>
  10. StopIteration

这里补充说明两点:

1.Python中内置的 iter和 next方法,其实就是执行的目标的 __iter__和 __next__方法。

  1. >>> l = [1, 2, 3]  # 这里是一个列表
  2. >>> i = iter(l)  # 使用Python内置的iter方法
  3. >>> i  # 得到一个迭代器
  4. <list_iterator object at 0x104db2a58>
  5. >>> next(i)  # 使用Python内置的next方法拿一个数据
  6. 1
  7. >>> next(i)  # 拿一个数据
  8. 2
  9. >>> next(i)  # 拿一个数据
  10. 3
  11. >>> next(i)  # 在迭代器 i 中再也拿不出数据了
  12. Traceback (most recent call last):
  13.  File "<stdin>", line 1, in <module>
  14. StopIteration

2.多次执行iter()或调用iter()得到的迭代器都是完全不同的对象。

你可以把它们想象成一次性塑料袋装的苹果,你执行一次iter()或调用一次iter(),你就得到一袋用一次性塑料袋装的苹果。(这个袋子是真的一次性,无法重复使用。)

  1. >>> l = [1, 2, 3]
  2. >>> i1 = iter(l)  # 得到一个迭代器
  3. >>> i2 = iter(l)  # 得到一个迭代器
  4. >>> i1 == i2  # 这两个迭代器是不同的迭代器
  5. False
  6. >>> id(i1) == id(i2)
  7. False
  8. >>> id(i1)
  9. 4376439496
  10. >>> id(i2)
  11. 4376439608

3.迭代器是有状态的

当你调用迭代器的 __next__()取值的时候,并且已经被取出的值不会再次取出。

  1. >>> l = [1, 2, 3]
  2. >>> i1 = iter(l)
  3. >>> i2 = iter(l)
  4. >>> next(i1)
  5. 1
  6. >>> next(i2)
  7. 1
  8. >>> next(i1)  # 能记住状态,从上一次结束的地方再开始
  9. 2

生成器(generator)

到现在为止,我们知道了可迭代对象和迭代器都是什么,并且也知道了它们的特点是什么。

那么生成器又是什么呢?

你现在回想一下,我们上面得到迭代器的过程是怎样的。 我们首先都是有一个可迭代对象,然后在这个可迭代对象基础上对它执行 __iter__()得到一个迭代器。 比如:我们先有一个列表 l=[1,2,3],然后在此基础上对它执行 __iter__()得到一个迭代器 i。在我们获取迭代器的时候,数据 l=[1,2,3]已经在内存中存在了。 也就是说,我们面前已经放着一袋真实的苹果,然后我们再把它变成一袋用一次性塑料袋装的苹果。

大概像是这样:

存在的数据 -得到-> 迭代器

  1. >>> l = [1, 2, 3]
  2. >>> i = iter(l)
  3. >>> i
  4. <list_iterator object at 0x104db2b70>

那我们如何针对现在还不存在的数据来获取对应的迭代器呢?也就是如何自己创造一个迭代器呢? 用生成器!生成器本质上就是一种特殊的迭代器。它也可以像迭代器那样依次取值。

未来的数据 -得到-> 生成器

比如:

我需要的数据是需要一系列运算得到的,比如10以内的奇数:

  1. >>> l = []  # 先找一个存放数据的容器
  2. >>> for i in range(11):
  3. ...   if i%2 != 0:  # 把符合条件的数据找到
  4. ...     l.append(i)  # 放进容器
  5. ...
  6. >>> l  # 得到结果
  7. [1, 3, 5, 7, 9]
  8. >>> i = iter(l)  # 再执行iter()
  9. >>> i  # 得到迭代器
  10. <list_iterator object at 0x104db2b70>

Python中有两种得到生成器的方式:

1.生成器表达式

在这之前我们先复习一下 列表推导式

  1. >>> l = [i for i in range(11) if i%2 != 0]
  2. >>> l
  3. [1, 3, 5, 7, 9]

生成器表达式就是把上面列表推导式的 []换成了 ():

  1. >>> g = (i for i in range(11) if i%2 != 0)
  2. >>> g
  3. <generator object <genexpr> at 0x104da47d8>

2.yield关键字

简单的计算逻辑我们可以使用生成器表达式,复杂一点的我们只能通过带有 yield关键字的函数来处理了。 当一个函数内部通过yield来返回值的时候,这个函数返回的就是生成器。

  1. >>> def func():  # 定义一个通过yield关键字返回值的函数
  2. ...   for i in range(11):
  3. ...     if i%2!=0:
  4. ...       yield i  # 返回符合条件的数据
  5. ...
  6. >>> g = func()  # 执行函数
  7. >>> g  # 得到一个生成器
  8. <generator object func at 0x104da4830>

应用:

因为生成器的数据不是事先已经存在于内存中的,所以它会比把结果先放进内容,再转换成迭代器的方式更节省内存。 也就是说,当你今后再遇到类似下面的逻辑代码时:

  1. def something():
  2.    result = []
  3.    for ... in ...:
  4.        result.append(i)
  5.    return result  # 把结果全都获得并且放进内存

你都可以把它改写成如下生成器的方式:

  1. def iter_something():
  2.    for ... in ...:
  3.        yield i  # 找到一个符合要求的就"返回"(不同于return)

概念重要,实际应用更重要。编程本身就是一项技能,需要不断地刻意练习。

时间: 2024-12-29 16:18:57

迭代器和生成器入门的相关文章

Python入门篇(八)之迭代器和生成器

迭代器和生成器 1.列表生成式 列表生成式即List Comprehensions,是Python内置的非常简单却强大的可以用来创建list的生成式.举个例子,要生成list [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]可以用list(range(1, 11)): >>> list(range(1, 11)) [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 但如果要生成[1x1, 2x2, 3x3, ..., 10x10]怎么做?方法一是循环: >

Python 入门基础11 --函数基础4 迭代器、生成器、枚举类型

今日目录: 1.迭代器 2.可迭代对象 3.迭代器对象 4.for循环迭代器 5.生成器 6.枚举对象 一.迭代器: 循环反馈的容器(集合类型) 每次重复即一次迭代,并且每次迭代的结果都是下一次迭代的初始值 l = [1, 2, 3] count = 0 while count<len(l): print(l[count]) count += 1 1.1 为什么要有迭代器? 字符串.列表.元组可以通过索引的方式迭代取出其中包含的元素 字典.集合.文件等类型,没有索引,只有通过不依赖索引的迭代方式

python控制结构、迭代器和生成器(个人笔记)

参考:https://docs.python.org/2.7/reference/compound_stmts.html#whilehttps://www.cnblogs.com/lclq/p/5586198.html (python的运算与表达式)https://www.zhihu.com/question/20829330 (python的迭代器)https://www.cnblogs.com/devin-guwz/p/5738676.html(python入门例题) python中的真假:

Python高级特性:迭代器和生成器 -转

在Python中,很多对象都是可以通过for语句来直接遍历的,例如list.string.dict等等,这些对象都可以被称为可迭代对象.至于说哪些对象是可以被迭代访问的,就要了解一下迭代器相关的知识了. 迭代器 迭代器对象要求支持迭代器协议的对象,在Python中,支持迭代器协议就是实现对象的__iter__()和next()方法.其中__iter__()方法返回迭代器对象本身:next()方法返回容器的下一个元素,在结尾时引发StopIteration异常. __iter__()和next()

Python的迭代器和生成器

先说迭代器,对于string.list.dict.tuple等这类容器对象,使用for循环遍历是很方便的就,在后台for语句对容器对象对象调用iteration()函数,这是python的内置函数,iter()会返回一个定义next()方法的迭代器对象,它在容器中逐个访问容器内元素,next()也是python的内置函数.在没有后续元素是,调用next()会抛出一个StopIteration异常 上面说的都是python自带的容器对象,它们都实现了相应的迭代器方法,自定义类的遍历怎么实现,方法是

python——迭代器、生成器、装饰器

迭代器 迭代器规则 迭代:重复做一些事很多次,就像在循环中那样. 不仅可以对字典和序列进行迭代,还可以对其他对象进行迭代:只要该对象实现了__iter__方法. __iter__方法会返回一个迭代器(iterator),所谓的迭代器就是具有next方法(这个方法在调用时不需要任何参数)的对象.在调用next方法时,迭代器会返回他的下一个值.如果next方法被调用,但迭代器没有值可以返回,就会引发一个StopIteration异常. 注意:迭代器规则在3.0中有一些变化.在新的规则中,迭代器对象应

python高级编程之迭代器与生成器

# -*- coding: utf-8 -*- # python:2.x __author__ = 'Administrator' #迭代器与生成器 #--------------------------------------- #迭代器基于2个方法 """ next:返回容器下一个项目 __iter__:返回迭代器本身 """ #通过内建函数和序列来创建 i=iter('abc') print i.next()#a print i.next(

python3 迭代器与生成器

pythom3 迭代器与生成器 迭代器'''迭代器是python最强大的功能之一,是访问集合元素的一种方式.迭代器是一个可以记住遍历的位置对象迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问玩结束.迭代器只能往前不会后退.迭代器有两个基本方法:iter()和next().字符串,列表或元组对象都可用于创建迭代器: ''' list=[1,2,6,3] it=iter(list)#创建迭代器对象 print(next(it))#结果1 print(next(it))#结果2 print(

Python之装饰器、迭代器和生成器

在学习python的时候,三大“名器”对没有其他语言编程经验的人来说,应该算是一个小难点,本次博客就博主自己对装饰器.迭代器和生成器理解进行解释. 为什么要使用装饰器 什么是装饰器?“装饰”从字面意思来谁就是对特定的建筑物内按照一定的思路和风格进行美化的一种行为,所谓“器”就是工具,对于python来说装饰器就是能够在不修改原始的代码情况下给其添加新的功能,比如一款软件上线之后,我们需要在不修改源代码和不修改被调用的方式的情况下还能为期添加新的功能,在python种就可以用装饰器来实现,同样在写