Python基础(四)——迭代器/对象,生成器
首先廖雪峰网站写的内容就我目前初步学习来说,已经相当详实,知识点平铺直叙让人易接受,所以以下内容均作为一种摘记记录以及补充。
1. 列表生成器
主要目的是创建 list 。多看例子就能清楚:
#列表生成基本使用
print(list(range(1,10,2))) #[1, 3, 5, 7, 9].生成1~9(左闭右开),相隔为2
print([t * t for t in range(1,10,3) if t % 2 == 0]) #[16].生成1~9相隔4,且是偶数的平方和
print([m + n for m in '' for n in '']) #['14', '15', '16', '24', '25', '26', '34', '35', '36'].全排列 #通过函数生成(其实与上几句类似)
def fun(x):
return x * 2
T = [fun(x) for x in [1,2,3,4]]
print(T) # [2, 4, 6, 8] 。这很类似用 T = map(fun, L) #生成dict列表
d = {'x': 'A', 'y': 'B', 'z': 'C'}
# for k, v in d.items():
# print(k, '=', v)
print([m + '=' + n for m,n in d.items()]) #['x=A', 'y=B', 'z=C'] #筛选单词,并全变小写
L = ['Hello', 'World', 18, 'Apple', None]
print([t.lower() for t in L if isinstance(t, str)]) #['hello', 'world', 'apple']
2. Iterable vs Iterator
iterable 是可迭代对象,iterator 是迭代器。两者都是 collection.abc 中得抽象类。iterator 继承自 iterable 。
- iterable 有常见得 list,dict,str,tuple 等或者自定义的类(该类必须实现抽象方法 _iter()_)。当一个可迭代对象作为参数调用自身的 iter() 方法时,会返回一个迭代器。迭代器拥有 _next()_ 抽象方法,可迭代对象没有,通过该方法就可以逐个得到 “序列” 中的各个值,不断调用 _next()_ 方法,最后会引起 StopIteration 异常报错,代表迭代结束了。同时迭代器还拥有 _iter()_ 方法,所以迭代器也是个可迭代对象。即所有的迭代器都是可迭代对象,但是可迭代对象并不都是迭代器,基本判断方法是是否调用 next() 方法,list,dect,str,tuple 都并不行,即不是迭代器。
我们可以通过 isinstance 来判断:
from collections.abc import Iterable,Iterator
t = [1,2,3] #列表
print(isinstance(t, Iterable)) #true
print(isinstance(t, Iterator)) #false
我们常用的 for...in [ ] 。就是利用了迭代器
from collections.abc import Iterable,Iterator
L = [1,2,3]
print(isinstance(L, Iterator)) #Flase
for t in L:
print(t, end=' ') #1 2 3
这是我们常写的代码,输出123。既然 L 不是迭代器为啥也能迭代输出呢。这就是在使用 for...in 的时候,Python 解释器主动将可迭代对象调用了 iter() 返回迭代器,即每次都是通过迭代器的 next() 方法进行输出。那么哪个异常 StopIteration 呢?异常应该被 for...in 内部处理了,并不显式的抛出。
我们换一种更明显的写法:
from collections.abc import Iterable,Iterator
L = [1,2,3]
print(isinstance(L, Iterator)) #false
T = L.__iter__()
print(isinstance(T, Iterator)) #true。现在T就是迭代器了,拥有了next()方法。
print(T.__next__()) #
print(T.__next__()) #
print(T.__next__()) #
print(T.__next__()) # StopIteration
结果和我们想的是一样的。或者再这样写
from collections.abc import Iterable,Iterator
L = [1,2,3]
print(isinstance(L, Iterator)) #false
T = iter(L)
while True:
try:
print(next(T), end=' ')
except StopIteration:
print('结束')
break
(点击图片查看原文)
3. 生成器和 yield
- 生成器是返回一个 generator iterator 的函数。但是这个函数中包含 yield 表达式,除此之外别无它异,用来产生一系列供 for 循环使用的值或者通过 next() 逐一获取。所以生成器一般也称为生成器函数。
- 生成迭代器 generator iterator 是由生成器 generator 创建的对象。每遇到 yield 会暂停(相当于return),并记住当前位置,之后在继续在记住的位置继续向下运行。而不同于普通函数每次都由上往下运行。
- 第一种创建生成器的方法:将列表生成式的 [ ] 换成 ( )
L = ( t * t for t in range(1,10))
print(L) #<generator object <genexpr> at 0x0000028D2F68B840>
print(next(L)) #
print(next(L)) #
for i in L: # 迭代输出
print(i)
- 当一个生成函数被调用时,返回一个迭代器,成为生成器。这个生成器来控制生成函数的执行,遇到 yield 就挂起,下次继续从 挂起处执行。前面说过迭代器有 next() 方法,所以这里的yield 就是干了 next() 方法的事。一样不断next 直到无数据 StopIteration。
- 第二种是通过定义函数:
def test():
print('')
yield
print('')
yield
print('')
yield t = test() # t 是生成器,生成器来控制函数
print(t) # <generator object test at 0x0000021EF6C5B840>
next(t) #
next(t) #
next(t) #
next(t) # StopIteration
可以通过 11~14 行看出,yield 起的作用就是挂起。第一次调用next() 方法,函数执行到第三句就停了,第二次调用 next() 执行到第五句。yield 就像是 OS 中的中断语句,保护现场--恢复现场。
再来看一个斐波那契例子:
#斐波那契数列
#常规写法一:
# def fib(max):
# n, a, b = 0, 0, 1
# while n < max:
# print(b)
# a, b = b, a + b
# n = n + 1
# return 'done'
#
# fib(6) #生成器写法二:
from collections.abc import Iterator,Iterable
def fib(max):
n, a, b = 0, 0, 1
while n < max:
yield b # yield 类似于return 将 b 返回
a, b = b, a + b
n = n + 1
return 'done' f = fib(6)
print(f) #<generator object fib at 0x00000124DDD8B840>
print(isinstance(f, Iterator)) #True。生成函数返回迭代器 for n in f:
print(n, end=' ') #1 1 2 3 5 8
通过观察24,25行可以知道,调用了 fib() 之后,函数并没有执行到尾(否则返回 str = 'done'),正如上文所说,返回的是一个 生成器,也就是调用生成函数(含 yield语句的)返回生成器,然后我们通过生成器来控制函数的执行。只有执行27行的 for...in 的时候,才会去执行15~21这段函数代码。
具体执行过程:第一次从16至18行停止,因为yield的存在,执行到18行就停了,然后返回一个值 b 给 for 循环,然后执行28行输出 b,然后next()迭代器继续从上次停止的地方的下一行19行继续执行(迭代器next()只要不是StopIteration 或者生成函数结束了,for 循环就得以继续),然后在while循环内,再次执行到18行停止,返回 b 给 for。继续重复,直至跳出while循环,fib() 这段生成器函数结束了,for...in 也就结束了。
# 生成器写法三
from collections.abc import Iterator,Iterable
def fib(max):
n, a, b = 0, 0, 1
while n < max:
yield b # yield 类似于return 将 b 返回
a, b = b, a + b
n = n + 1 f = fib(3)
print(f) #<generator object >
print(isinstance(f, Iterator)) #True。生成函数返回迭代器
print(next(f)) #
print(next(f)) #
print(next(f)) #
print(next(f)) # StopIteration
4.生成器send()方法
stackoverflow 上还有关于生成 yield 配合使用 send()的方法。查阅官网,send(value) 函数意思:恢复执行,并向生成器发送一个值,value 参数将被当作 yield 表达式结果。
def test():
while True:
x = yield
yield x * 2 g = test()
print(next(g)) # none
print(g.send(12)) #24
我们已经知道 yield 可以当作return来理解。
首先第六行创建了 g (生成器),第七行输出 none,因为执行第七行,也就是去执行test()函数了,函数顺利执行到第三行,3 = yield 明显是我们学的赋值语句,难道是将yield赋值给3?不是的。先解释输出的none,因为没有参数写在yield的右边,即没有参数返回,所以第七行输出 None。同时因为yield存在而停止继续。
而第八行:遇到g.send() 会继续执行上次执行到第三行的地方,这里传入的参数12就是赋值给x的。所以再往下第四行,yiled看成return 返回12*2,同时test()函数被挂起,返回24给第八行。至此函数结束。
又比如:
def test(x):
while True:
x *= 2
x = yield x g = test(3)
print(next(g)) #
print(g.send(12)) #
第四行意思:先看右边yield x 就是返回 x 。再看左边 x = yield 就是赋值给 x 。所以不难理解了。不解释了。
5. 补充(点击图片查看原文)
Python基础(四)——迭代器/对象,生成器的更多相关文章
- python基础之迭代器、生成器、装饰器
一.列表生成式 a = [0,1,2,3,4,5,6,7,8,9] b = [] for i in a: b.append(i+1) print(b) a = b print(a) --------- ...
- Python基础之迭代器、生成器
一.迭代器: 1.迭代:每一次对过程的重复称为一次“迭代”,而每一次迭代得到的结果会作为下一次迭代的初始值.例如:循环获取容器中的元素. 2.可迭代对象(iterable): 1)定义:具有__ite ...
- python基础之迭代器与生成器
一.什么是迭代器: 迭代是Python最强大的功能之一,是访问集合元素的一种方式. 迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束. 迭代器是一个可以记住遍历的位置的对象. 迭代器的 ...
- python基础8 -----迭代器和生成器
迭代器和生成器 一.迭代器 1.迭代器协议指的是对象必须提供一个next方法,执行该方法要么返回迭代中的下一项,要么就引起一个StopIteration异常,以终止迭代 (只能往后走不能往前退) 2. ...
- 【Python基础】迭代器、生成器
迭代器和生成器 迭代器 一 .迭代的概念 #迭代器即迭代的工具,那什么是迭代呢? #迭代是一个重复的过程,每次重复即一次迭代,并且每次迭代的结果都是下一次迭代的初始值 while True: #只是单 ...
- Python基础之迭代器和生成器
阅读目录 楔子 python中的for循环 可迭代协议 迭代器协议 为什么要有for循环 初识生成器 生成器函数 列表推导式和生成器表达式 本章小结 生成器相关的面试题 返回顶部 楔子 假如我现在有一 ...
- 1.17 Python基础知识 - 迭代器和生成器初识
可循环迭代的对象称为可迭代对象,迭代器和生成器函数是可迭代对象. 列表解析表达式:可以简单高效处理一个可迭代对象,并生成结果列表 示例代码: [ i ** 2 for i in range(10) ] ...
- Python高手之路【九】python基础之迭代器与生成器
迭代器与生成器 1.迭代器 迭代器是访问集合元素的一种方式.迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束.迭代器只能往前不会后退,不过这也没什么,因为人们很少在迭代途中往后退.另外 ...
- python 基础(五) 迭代器与生成器
迭代器和生成器 迭代器 iterator (1) 迭代对象: 可以直接作用于for循环的 称为可迭代对象(iterable)可以通过 isinstance 判断是否属于可迭代对象 可以直接作用于for ...
- 7th,Python基础4——迭代器、生成器、装饰器、Json&pickle数据序列化、软件目录结构规范
1.列表生成式,迭代器&生成器 要求把列表[0,1,2,3,4,5,6,7,8,9]里面的每个值都加1,如何实现? 匿名函数实现: a = map(lambda x:x+1, a) for i ...
随机推荐
- (转)CentOS 5.5 64bit 编译安装Adobe FlashMediaServer 3.5
http://download.macromedia.com/pub/flashmediaserver/updates/4_0_2/Linux_32bit/FlashMediaServer4.tar. ...
- Java for LeetCode 094 Binary Tree Inorder Traversal
解题思路: 中序遍历,左子树-根节点-右子树 JAVA实现如下: public List<Integer> inorderTraversal(TreeNode root) { List&l ...
- Data Structure Binary Tree: Level order traversal in spiral form
http://www.geeksforgeeks.org/level-order-traversal-in-spiral-form/ #include <iostream> #includ ...
- haproxy 修改 访问路径
# 匹配 jsessionid,并去除 jessionid参数reqrep ^([^\ :]*)\ /a/test.html;jsessionid=.*\?(.*) \1\ /b/test.html? ...
- c# 实现WebSocket
用C# ASP.NET MVC 实现WebSocket ,对于WebSocket想必都很了解了,不多说. 东西做的很粗糙 只能实现基本的聊天功能,不过基本的通信实现了,那么后序的扩展应该也不难(个人这 ...
- CSS实现简单无缝滚动
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- 牛客网暑期ACM多校训练营(第三场)G:Coloring Tree(函数的思想)
之前两次遇到过函数的思想的题,所以这次很敏感就看出来了.可以参考之前的题: https://www.cnblogs.com/hua-dong/p/9291507.html Christmas is c ...
- k8s-flannel容器集群网络部署
[root@k8s-master src]# wget https://github.com/coreos/flannel/releases/download/v0.9.1/flannel-v0.9. ...
- 「LuoguP1144」 最短路计数(dijkstra
题目描述 给出一个NN个顶点MM条边的无向无权图,顶点编号为1-N1−N.问从顶点11开始,到其他每个点的最短路有几条. 输入输出格式 输入格式: 第一行包含22个正整数N,MN,M,为图的顶点数与边 ...
- C++之MutexLock和MutexLockGuard封装
noncopyable.h #ifndef __WD_NONCOPYABLE_H__ #define __WD_NONCOPYABLE_H__ namespace wd { class Noncopy ...