想要搞明白什么是迭代器,首先要了解几个名词:容器(container)、迭代(iteration)、可迭代对象(iterable)、迭代器(iterator)、生成器(generator)。

看图是不是更清楚点呢......

一 容器(container)

容器是一种把多个元素组织在一起的数据结构,容器中的元素可以逐个地迭代获取,可以用innot in关键字判断元素是否包含在容器中。通常这类数据结构把所有的元素存储在内存中(也有一些特例,并不是所有的元素都放在内存,比如迭代器和生成器对象)在Python中,常见的容器对象有:

  • list, deque, ….
  • set, frozensets, ….
  • dict, defaultdict, OrderedDict, Counter, ….
  • tuple, namedtuple, …
  • str

容器比较容易理解,因为你就可以把它看作是一个盒子、一栋房子、一个柜子,里面可以塞任何东西。从技术角度来说,当它可以用来询问某个元素是否包含在其中时,那么这个对象就可以认为是一个容器,比如 list,set,tuples都是容器对象。

print( 1 in [1, 2, 3])      # lists
# True
print(4 not in [1, 2, 3])
# True
print(1 in {1, 2, 3}) # sets
# True
print(4 not in {1, 2, 3})
# True
print(1 in (1, 2, 3)) # tuples
# True
print(4 not in (1, 2, 3))
# True # 询问某元素是否在dict中用dict的中key: d = {1: 'foo', 2: 'bar', 3: 'qux'}
print(1 in d)
# True
print('foo' not in d) # 'foo' 不是dict中的元素
# True # 询问某substring是否在string中: s = 'foobar'
print('b' in s)
# True
print('x' not in s)
# True
print('foo' in s)
# True

尽管绝大多数容器都提供了某种方式来获取其中的每一个元素,但这并不是容器本身提供的能力,而是可迭代对象赋予了容器这种能力,当然并不是所有的容器都是可迭代的,比如:Bloom filter,虽然Bloom filter可以用来检测某个元素是否包含在容器中,但是并不能从容器中获取其中的每一个值,因为Bloom filter压根就没把元素存储在容器中,而是通过一个散列函数映射成一个值保存在数组中。  

二 迭代(iteration)

什么是迭代,我的理解如下:

  • 第一,迭代需要重复进行某一操作

  • 第二,本次迭代的要依赖上一次的结果继续往下做,如果中途有任何停顿,都不能算是迭代

下面来看几个例子,能更好理解迭代的含义。

# 实例1
# 非迭代
count = 0
while count < 10:
print("hello world")
count += 1 # 实例2
# 迭代
count = 0
while count < 10:
print(count)
count += 1

实例1,仅仅只是在重复一件事,那就是不停的打印"hello world",并且,这个打印的结果并不依赖上一次输出的值。而实例2,就很好地说明迭代的含义,重复+继续。 

三 可迭代对象 (iterable)

通俗的说就是在每一种数据类型对象中,都会有有一个__iter__()方法,正是因为这个方法,才使得这些基本数据类型变为可迭代。

当我们运行以下代码的时候:

x = [1,2,3]
for elem in x:
print(elem) # 运行结果:
# 1
# 2
# 3

实际调用过程如下:

那么如何判断一个对象是否是可迭代呢?使用collections模块的Iterable类型判断

from collections import Iterable

print(isinstance('abc', Iterable)) # str是否可迭代
# True
print(isinstance([1,2,3], Iterable)) # list是否可迭代
# True
print(isinstance(123, Iterable)) # 整数是否可迭代
# False  

四 迭代器(iterator)

通俗来讲任何具有__next__()方法的对象都是迭代器,对迭代器调用__next__()方法可以获取下一个值。

五 生成器(generator)

生成器是一个用简单的方式来完成迭代。简单来说,Python的生成器是一个返回可以迭代对象的函数。

那要怎么创建生成器呢,很简单的,在一般函数中使用yield关键字,可以实现一个最简单的生成器,此时这个函数变成一个生成器函数。yieldreturn返回相同的值,区别在于return返回后,函数状态终止,而yield会保存当前函数的执行状态,在返回后,函数又回到之前保存的状态继续执行。

看一下简单的生成器实例吧:

def test():
yield 1
yield 2
yield 3
g=test()
print('来自函数',g)
print(g.__next__())
print(g.__next__()) # 运行结果
# 来自函数 <generator object test at 0x000000000072B8E0>
# 1
# 2 

生成器与一般函数有什么区别呢?

  • 生成器函数包含一个或者多个yield
  • 当调用生成器函数时,函数将返回一个对象,但是不会立刻向下执行
  • __iter__()__next__()方法等是自动实现的,所以我们可以通过next()方法对对象进行迭代
  • 一旦函数被yield,函数会暂停,控制权返回调用者
  • 局部变量和它们的状态会被保存,直到下一次调用
  • 函数终止的时候,StopIteraion会被自动抛出

来个例子看一下吧:

# 简单的生成器函数
def my_gen():
n=1
print("first")
# yield区域
yield n n+=1
print("second")
yield n n+=1
print("third")
yield n a=my_gen()
print("next method:")
# 每次调用a的时候,函数都从之前保存的状态执行
print
print(next(a))(next(a))
print(next(a)) # 运行结果
# next method:
# first
# 1
# second
# 2
# third
# 3 print("for loop:")
# 与调用next等价的
b=my_gen()
for elem in my_gen():
print(elem) # 运行结果
# for loop:
# first
# 1
# second
# 2
# third
# 3

来看看使用循环的生成器

# 逆序yield出对象的元素
def rev_str(my_str):
length=len(my_str)
for i in range(length-1,-1,-1):
yield my_str[i] for char in rev_str("hello"):
print(char) # 运行结果
# o
# l
# l
# e
# h

六 生成器表达式

Python中,有一个列表生成方法,也就是常说的列表解析,提到列表解析就先要弄明白三元表达式的概念,什么是三元表达式呢?来个实例看看吧

egg_list=[]
for i in range(10):
egg_list.append('鸡蛋%s' %i)
print(egg_list)
# ['鸡蛋0', '鸡蛋1', '鸡蛋2', '鸡蛋3', '鸡蛋4', '鸡蛋5', '鸡蛋6', '鸡蛋7', '鸡蛋8', '鸡蛋9'] # 使用三元表达式替换如上代码
l=['鸡蛋%s' %i for i in range(10)]
print(l)
# ['鸡蛋0', '鸡蛋1', '鸡蛋2', '鸡蛋3', '鸡蛋4', '鸡蛋5', '鸡蛋6', '鸡蛋7', '鸡蛋8', '鸡蛋9'] l1=['鸡蛋%s' %i for i in range(10) if i > 5 ]
print(l1)
# ['鸡蛋6', '鸡蛋7', '鸡蛋8', '鸡蛋9'] # l2=['鸡蛋%s' %i for i in range(10) if i > 5 else i] #没有四元表达式
# print(l2) l3=['鸡蛋%s' %i for i in range(10) if i < 5]
print(l3)
# ['鸡蛋0', '鸡蛋1', '鸡蛋2', '鸡蛋3', '鸡蛋4']

了解了三元表达式,我们再来看看什么是生成器表达式,其实很简单,就是把三元表达式中的[]换成()即可。

a=(x for x in range(10))
b=[x for x in range(10)]
# 这是错误的,因为生成器不能直接给出长度
# print("length a:",len(a)) # 输出列表的长度
print("length b:",len(b))
# length b: 10
b=iter(b)
# 二者输出等价,不过b是在运行时开辟内存,而a是直接开辟内存
print(next(a))
print(next(b))

Python3 迭代器和生成器的更多相关文章

  1. Python3+迭代器与生成器

    转载Python3 迭代器与生成器 迭代器 迭代是Python最强大的功能之一,是访问集合元素的一种方式. 迭代器是一个可以记住遍历的位置的对象. 迭代器对象从集合的第一个元素开始访问,直到所有的元素 ...

  2. python014 Python3 迭代器与生成器

    Python3 迭代器与生成器迭代器迭代是Python最强大的功能之一,是访问集合元素的一种方式..迭代器是一个可以记住遍历的位置的对象.迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结 ...

  3. python3: 迭代器与生成器(1)

    1. 手动遍历迭代器 你想遍历一个可迭代对象中的所有元素,但是却不想使用for循环. >>> items = [1, 2, 3] >>> # Get the ite ...

  4. python3迭代器和生成器

    1.手动访问迭代器中的元素 #要手动访问迭代器中的元素,可以使用next()函数 In [3]: with open('/etc/passwd') as f: ...: try: ...: while ...

  5. Python3 迭代器与生成器 - 学习笔记

    可迭代对象(Iterable) 迭代器(Iterator) 定义 迭代器和可迭代对象的区别 创建一个迭代器 创建一个迭代器类 使用内置iter()函数 StopIteration异常 生成器(gene ...

  6. Python3迭代器与生成器

    迭代器 迭代是Python最强大的功能之一,是访问集合元素的一种方式. 迭代器是一个可以记住遍历的位置的对象. 迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束.迭代器只能往前不会后退 ...

  7. python3 迭代器,生成器

    一 .什么是迭代 1. 重复 2.下次重复一定是基于上一次的结果而来 while True: cmd=input(':') print(cmd) l=[1,2,3,4] count=0 while c ...

  8. python系列九:python3迭代器和生成器

    #!/usr/bin/python import sys '''迭代器是一个可以记住遍历的位置的对象.迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束.迭代器只能往前不会后退.迭代器有 ...

  9. 吴裕雄--天生自然python学习笔记:Python3 迭代器与生成器

    迭代器 迭代是Python最强大的功能之一,是访问集合元素的一种方式. 迭代器是一个可以记住遍历的位置的对象. 迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束.迭代器只能往前不会后退 ...

随机推荐

  1. 面试官问你JS基本类型时他想知道什么?

    面试的时候我们经常会被问答js的数据类型.大部分情况我们会这样回答包括:1.基本类型(值类型或者原始类型): Number.Boolean.String.NULL.Undefined以及ES6的Sym ...

  2. ASP.net 加载不了字体Failed to load resource: the server responded with a status of 404 (Not Found)

    在bootstrap下加载不了字体内容.出现下列错误. 1.打开IIS找到部署的网站,点击MIME类型,把.woff和.woff2两个类型分别添加到新类型中,重启网站即可.  

  3. HTML5视频播放练习:鼠标经过视频播放,鼠标移除停止播放,再次经过继续播放。

    随着HTML5的广泛应用,在一些网站中,经常看到有些预览的短视频预览,鼠标经过就会播放,移除就会停止播放,再次移进去就会继续播放. 自己也研究着做一个比较简单的类似的练习. 视频可以自己到包图网下载, ...

  4. Struts2速记手册

    工作原理 Action类 Action类 普通Action类 私有属性及getter.setter(处理请求参数) execute()方法(处理请求)   实现Action接口 提供常量   继承Ac ...

  5. MySQL慢日志查询实践

    慢日志查询作用 慢日志查询的主要功能就是,记录sql语句中超过设定的时间阈值的查询语句.例如,一条查询sql语句,我们设置的阈值为1s,当这条查询语句的执行时间超过了1s,则将被写入到慢查询配置的日志 ...

  6. C# 操作word 模板 值 替换

    1.引用 aspose.words   dll 2.word 使用doc 3.给word 模板中添加要替换位置的 书签 .引用 aspose.words dll .word 使用doc .给word ...

  7. Delphi 高效读写锁

    本人设计了一个高效读写锁,可实现多个线程读一个线程写的锁,应该比Delphi自带的读写锁高效,本人没有做对比测试. 本文的锁不可以在一个线程里重入,否则会锁死,另外读写锁最多支持65535个线程同时读 ...

  8. [FreeRTOS入门] 1.CubeMX中FreeRTOS配置参数及理解

    1.有关优先级 1.1 Configuration --> FreeRTOS MAX_PRIORITIES 设置任务优先级的数量:配置应用程序有效的优先级数目.任何数量的任务都可以共享一个优先级 ...

  9. 短连接、长连接、轮询、长轮询、WebSocket

    短连接 建立连接——数据传输——关闭连接...建立连接——数据传输——关闭连接 定义:短连接是指通讯双方有数据交互时,就建立一个连接,数据发送完成后,则断开此连接,即每次连接只完成一项业务的发送. 应 ...

  10. Selenium_python自动化跨浏览器执行测试(简单多线程案例)

    发生背景: 跨浏览器测试是功能测试的一个分支,用以验证web应用在不同浏览器上的正常工作,通常情况下,我们都期望web类应用能够被我们的用户在任何浏览器上使用,例如有的人喜欢IE浏览器上使用,有的人喜 ...