Python复习笔记(八)迭代器和生成器和协程
1. 迭代器
1.1 可迭代对象
判断xxx_obj是否可以迭代
在第1步成立的前提下,调用 iter 函数得到 xxx_obj 对象的 __iter__ 方法的返回值
__iter__ 方法的返回值是一个迭代器
如果想要一个对象称为一个 可以迭代的对象,即可以使用for,必须实现 __iter__方法
__iter__ 中必须返回对象的引用【要这个对象有__iter__和__next__方法, 实际上取的__next__的返回值】
迭代器结束,需要抛出一个 StopIteration 异常。
from collections import Iterable
from collections import Iterator
import time class Classmate(object):
def __init__(self):
self.names = list() def add(self, name):
self.names.append(name) def __iter__(self):
# 如果想要一个对象称为一个 可以迭代的对象,即可以使用for,必须实现 __iter__方法
return ClassIterator(self) # 必须返回 class ClassIterator(object): def __init__(self, obj):
self.obj = obj
self.current_num = 0 def __iter__(self):
pass def __next__(self):
if self.current_num < len(self.obj.names):
ret = self.obj.names[self.current_num]
self.current_num += 1
return ret
else:
raise StopIteration classmate = Classmate() classmate.add("王1")
classmate.add("李2")
classmate.add("张3") # print("classmate是否是可以迭代的对象: ", isinstance(classmate, Iterable))
# classmate_iterator = iter(classmate)
# print("classmate_iterator是否是迭代器: ", isinstance(classmate_iterator, Iterator)) # iter
# print(next(classmate_iterator))
#
for name in classmate:
print(name)
time.sleep(1)
王1
李2
张3
1.2 调用自己的__next__方法
from collections import Iterable
from collections import Iterator
import time class Classmate(object):
def __init__(self):
self.names = list()
self.current_num = 0 def add(self, name):
self.names.append(name) # 判断是否可以迭代
def __iter__(self):
# 如果想要一个对象称为一个 可以迭代的对象,即可以使用for,必须实现 __iter__方法
return self # 调用返回对象的__next__方法(这里调用自己的__next__方法 def __next__(self):
if self.current_num < len(self.names):
ret = self.names[self.current_num]
self.current_num += 1
return ret
else:
raise StopIteration # 停止迭代 classmate = Classmate() classmate.add("王1")
classmate.add("李2")
classmate.add("张3") # print("classmate是否是可以迭代的对象: ", isinstance(classmate, Iterable))
# classmate_iterator = iter(classmate)
# print("classmate_iterator是否是迭代器: ", isinstance(classmate_iterator, Iterator)) # iter
# print(next(classmate_iterator))
#
for name in classmate:
print(name)
time.sleep(1)
王1
李2
张3
生成斐波那契数列
class Fibnacci(object):
def __init__(self, all_num):
self.all_nums = all_num
self.current_num = 0
self.a = 0
self.b = 1 def __iter__(self):
return self def __next__(self):
if self.current_num < self.all_nums:
ret = self.a self.a, self.b = self.b, self.a+self.b
self.current_num += 1 return ret
else:
raise StopIteration fibo = Fibnacci(10) for num in fibo:
print(num)
2. 生成器--一种特殊迭代器
2.1 创建生成器1:()
2.2 创建生成器2:yield
def create_num(all_num):
# a = 1
# b = 1
a, b = 0, 1
current_num = 0
while current_num < all_num:
yield a # 如果一个函数中有yield语句,那么这个就不在是函数,而是一个生成器的模板
a, b = b, a + b
current_num += 1 if __name__ == '__main__':
# 如果在调用create_num的时候,发现这个函数有yield,此时不是调用函数,而是创建一个生成器对象
obj = create_num(10)
for num in obj:
print(num)
注意:yield的工作流程
2.3 两个生成器之间没有影响
2.4 通过异常判断生成器已结束
2.5 生成器获得return的值
2.6 send使用--启动生成器
def create_num(all_num):
a, b = 0, 1
current_num = 0
while current_num < all_num:
res = yield a
print(">>>>ret>>>>", res)
a, b = b, a + b
current_num += 1 if __name__ == '__main__':
obj = create_num(4) # obj.send(None) # send一般不会放到第一次启动生成器,如果非要如此,传递None ret = next(obj)
print(ret) ret = obj.send("hhhhh")
print(ret) # send里面的数据,会传递给第5行,当作yield a的结果,然后res保存这个结果..
# send的结果是下一次调用yield时,yield后面的值
ret = obj.send(None)
print(ret) ret = obj.send(None)
print(ret)
注意:send不要放第一次
2.7 yield和return区别
yield可以暂停函数执行,且下一次执行时候恢复
2.8 迭代器和生成器作用
- 迭代器: 减少内存空间, 能实现循环
- 生成器: 能让一个函数看上去能暂停执行
- 都是保证生成数据代码, 不是保存结果
生成器(yield): 实现多任务 !
3. 多任务-协程(yield执行)
进程占资源最多, 其次线程, 协程占资源最少!
#!/bin/python3
# -*- coding=utf-8 -*- import time def task_1():
while True:
print("------1-------")
time.sleep(0.1)
yield def task_2():
while True:
print("------2------")
time.sleep(0.2)
yield def main():
t1 = task_1()
t2 = task_2()
while True:
next(t1)
next(t2) if __name__ == "__main__":
main()
并行: 有两个任务, 但是有四个CPU的核, 一个任务占一个核, 每个都在做
并发: 有很多任务, 但是只有两个核, 所以 交替执行
4. greenlet实现多任务(核心还是yield)
#!/bin/python3
# -*- encoding=utf-8 -*- from greenlet import greenlet import time def test1():
while True:
print("----A----")
gr2.switch()
time.sleep(0.5) def test2():
while True:
print("----B----")
gr1.switch()
time.sleep(0.5) gr1 = greenlet(test1)
gr2 = greenlet(test2) # 切换到gr1中执行
gr1.switch()
5. gevent实现协程(更强大,常用)
#!/bin/python3
# -*-encoding=utf-8-*- import gevent
import time def f1(n):
for i in range(n):
print(gevent.getcurrent(), i)
gevent.sleep(0.5) def f2(n):
for i in range(n):
print(gevent.getcurrent(), i)
gevent.sleep(0.5) def f3(n):
for i in range(n):
print(gevent.getcurrent(), i)
gevent.sleep(0.5) print("----1-----")
g1 = gevent.spawn(f1, 5)
print("----2-----")
g2 = gevent.spawn(f2, 5)
print("----3-----")
g3 = gevent.spawn(f3, 5)
print("----4-----") g1.join()
g2.join()
g3.join()
gevent遇到延时操作就切换, 利用了等待耗时的操作, 去做其他的事情
如下: 加入monkey.patch_all()则无须将 time.sleep()改成 gevent.sleep()
#!/bin/python3
# -*-encoding=utf-8-*- import gevent
from gevent import monkey
import time monkey.patch_all() def f1(n):
for i in range(n):
print(gevent.getcurrent(), i)
time.sleep(0.5)
# gevent.sleep(0.5) def f2(n):
for i in range(n):
print(gevent.getcurrent(), i)
time.sleep(0.5)
# gevent.sleep(0.5) def f3(n):
for i in range(n):
print(gevent.getcurrent(), i)
time.sleep(0.5)
# gevent.sleep(0.5) print("----1-----")
g1 = gevent.spawn(f1, 5)
print("----2-----")
g2 = gevent.spawn(f2, 5)
print("----3-----")
g3 = gevent.spawn(f3, 5)
print("----4-----") g1.join()
g2.join()
g3.join()
如下: 将需要join的代码, 写成列表, 简洁
#!/bin/python3
# -*-encoding=utf-8-*- import gevent
from gevent import monkey
import time monkey.patch_all() def f1(n):
for i in range(n):
print(gevent.getcurrent(), i)
time.sleep(0.5)
# gevent.sleep(0.5) def f2(n):
for i in range(n):
print(gevent.getcurrent(), i)
time.sleep(0.5)
# gevent.sleep(0.5) def f3(n):
for i in range(n):
print(gevent.getcurrent(), i)
time.sleep(0.5)
# gevent.sleep(0.5) gevent.joinall([
gevent.spawn(f1, 5),
gevent.spawn(f2, 5),
gevent.spawn(f3, 5)
])
6. 并发下载器
#!/bin/python3
#-*- encoding=utf-8 -*- import gevent
import urllib.request
from gevent import monkey monkey.patch_all() def downloader(img_name, img_url): req = urllib.request.urlopen(img_url) img_content = req.read() with open("./img/"+ img_name, "wb") as f:
f.write(img_content) def main():
gevent.joinall([
gevent.spawn(downloader, "1.jpg", 'https://rpic.douyucdn.cn/asrpic/190417/5440020_3968619_65b10_2_2142.jpg'),
gevent.spawn(downloader, '2.png', "https://rpic.douyucdn.cn/asrpic/190417/594613_2143.png")
]) if __name__=="__main__":
main()
7. 进程/线程/协程对比
进程: 耗费资源最多, 进程里一定有一个线程, 默认线程称为主线程。进程是资源分配的单位。(最稳定, 耗费资源最多)
线程: 线程是操作系统调度的单位. 线程切换需要的资源一般, 效率一般 (不考虑GIL情况)
协程: 协程切换任务资源很小, 效率高;
特点: 在等待某个资源到来 期间, 去执行其他代码....多线程里有很多网络堵塞, 推荐先用协程 !
- 多进程、多线程根据cpu核数不一样 可能是并行的, 但是协程是在一个线程中, 所以是并发的!
Python复习笔记(八)迭代器和生成器和协程的更多相关文章
- python基础----迭代器、生成器、协程函数及应用(面向过程实例)
一.什么是迭代器协议 1.迭代器协议是指:对象必须提供一个next方法,执行该方法要么返回迭代中的下一项,要么就引起一个StopIteration异常,以终止迭代 (只能往后走不能往前退) 2.可迭代 ...
- python入门20180717-迭代器、生成器和协程
迭代器.生成器和协程 python中任意的对象,只要它定义了可以返回一个迭代器的__iter__方法,或者支持下标索引的_getitem_方法,那么它就是一个可迭代对象. 可迭代的对象不一定就是迭代器 ...
- python学习笔记四 迭代器,生成器,装饰器(基础篇)
迭代器 __iter__方法返回一个迭代器,它是具有__next__方法的对象.在调用__next__方法时,迭代器会返回它的下一个值,若__next__方法调用迭代器 没有值返回,就会引发一个Sto ...
- python学习笔记-(十四)进程&协程
一. 进程 1. 多进程multiprocessing multiprocessing包是Python中的多进程管理包,是一个跨平台版本的多进程模块.与threading.Thread类似,它可以利用 ...
- python学习笔记11 ----线程、进程、协程
进程.线程.协程的概念 进程和线程是操作系统中两个很重要的概念,对于一般的程序,可能有若干个进程,每一个进程有若干个同时执行的线程.进程是资源管理的最小单位,线程是程序执行的最小单位(线程可共享同一进 ...
- Python学习笔记010_迭代器_生成器
迭代器 迭代就类似于循环,每次重复的过程被称为迭代的过程,每次迭代的结果将被用来作为下一次迭代的初始值,提供迭代方法的容器被称为迭代器. 常见的迭代器有 (列表.元祖.字典.字符串.文件 等),通常 ...
- python学习笔记之线程、进程和协程(第八天)
参考文档: 金角大王博客:http://www.cnblogs.com/alex3714/articles/5230609.html 银角大王博客:http://www.cnblogs.com/wup ...
- 完全理解 Python 迭代对象、迭代器、生成器(转)
完全理解 Python 迭代对象.迭代器.生成器 本文源自RQ作者的一篇博文,原文是Iterables vs. Iterators vs. Generators » nvie.com,俺写的这篇文章是 ...
- 完全理解 Python 迭代对象、迭代器、生成器
完全理解 Python 迭代对象.迭代器.生成器 2017/05/29 · 基础知识 · 9 评论 · 可迭代对象, 生成器, 迭代器 分享到: 原文出处: liuzhijun 本文源自RQ作者 ...
随机推荐
- JAVA 获取指定网址的IP地址 实例
如今买票是一大难事,在高峰时段 打开12306网站,慢的像蜗牛,想到以前用修改hosts文件来登录Google(Hosts是一个没有扩展名的系统文件,可以用记事本等工具打开,其作用就是将一些常用的网址 ...
- luogu1983 车站分级 (拓扑排序)
对每趟车建一个虚点p,对于不停车的x,连边(x,p,1):对于停车的y,连边(p,y,0)有一条边(a,b,l)就是说b-a>=l由于题目保证一定能走,直接拓扑序dp算最大的就行了 #inclu ...
- Neko's loop HDU-6444(网络赛1007)
题意就是给出n个数,在n个数上每次跳k个数,最多可以跳m次,你可以选择跳任意次,也可以都不跳,问你为了达到目标了快乐值至少在开始的需要多少快乐值. 题目可以转换成找出循环节,然后再循环节上疯狂试探我可 ...
- Who Gets the Most Candies? POJ - 2886 (线段树)
按顺时针给出n个小孩,n个小孩每个人都有一个纸,然后每个人都有一个val,这个val等于自己的因子数,如果这个val是正的,那就顺时针的第val个孩子出去,如果是负的话,就逆时针的第val个孩子出去, ...
- NOI2009管道取珠(dp)
题意:给定两列球,可以从任意一列球的末尾弹出一个球,最后会得到一个序列,设第i种序列可以被a[i]种操作产生,那么会产生a[i]^2的贡献,求贡献和. Solution: 首先我们观察a[i]^2的含 ...
- 洛谷P3709 大爷的字符串
题意:多次求区间众数的出现次数. 解: 这题居然可以莫队...... 首先开个桶.然后还要开个数组,cnt[i]表示出现i次的数有多少个. 然后就可以O(1)修改了. #include <cst ...
- Java实现二叉树的前序、中序、后序、层序遍历(递归方法)
在数据结构中,二叉树是树中我们见得最多的,二叉查找树可以加速我们查找的效率,那么输出一个二叉树也变得尤为重要了. 二叉树的遍历方法分为四种,分别为前序遍历.中序遍历.后序.层序遍历.下图即为一 ...
- 第三十四节,目标检测之谷歌Object Detection API源码解析
我们在第三十二节,使用谷歌Object Detection API进行目标检测.训练新的模型(使用VOC 2012数据集)那一节我们介绍了如何使用谷歌Object Detection API进行目标检 ...
- python config.ini的应用
config.ini文件的结构是以下这样的:结构是"[ ]"之下是一个section,一部分一部分的结构.以下有三个section,分别为section0,section1,sec ...
- 【非专业前端】vue+element+webpack
先点这里(- ̄▽ ̄)- 环境搭建 默认你已经安装了node.js 下面安装vue和webpack npm install -g @vue/cli npm install -g @vue/cli-ini ...