Python 生成器和协程
2020-12-13 03:26
标签:date cond stop https print 直接 dia setattr 结束 迭代是Python最强大的功能之一,是访问集合元素的一种方式。 迭代器是一个可以记住遍历的位置的对象。 迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退。 迭代器有两个基本的方法:iter() 和 next()。 字符串,列表,元组,集合、字典、range()、文件句柄等可迭代对象(iterable)都可用于创建迭代器: 迭代器对象可以使用常规for语句进行遍历: 也可以使用 next() 函数: 把一个类作为一个迭代器使用需要在类中实现两个方法 __iter__() 与 __next__() 。 如果你已经了解的面向对象编程,就知道类都有一个构造函数,Python 的构造函数为 __init__(), 它会在对象初始化的时候执行。 创建一个返回数字的迭代器(计数器),初始值为 1,逐步递增 1: StopIteration 异常用于标识迭代的完成,防止出现无限循环的情况,在 __next__() 方法中我们可以设置在完成指定循环次数后触发 StopIteration 异常来结束迭代。 那么如何判断一个对象是否是可迭代对象? 在 Python 中,使用了 yield 的函数被称为生成器(generator)。 跟普通函数不同的是,生成器是一个返回迭代器的函数,只能用于迭代操作,更简单点理解生成器就是一个迭代器。 在调用生成器运行的过程中,每次遇到 yield 时函数会暂停并保存当前所有的运行信息,返回 yield 的值, 并在下一次执行 next() 方法时从当前位置继续运行。 调用一个生成器函数,返回的是一个迭代器对象。 yield Vs return: 以下实例使用 yield 实现斐波那契数列: send向生成器中发送数据。send的作用相当于next,只是在驱动生成器继续执行的同时还可以向生成器中传递数据。 yield from 将一个可迭代对象变成一个迭代器返回,也可以说,yield from关键字可以直接返回一个生成器 更容易使用,代码量较小内存使用更加高效。比如: 根据维基百科给出的定义,“协程 是为非抢占式多任务产生子程序的计算机程序组件,协程允许不同入口点在不同位置暂停或开始执行程序”。从技术的角度来说,“协程就是你可以暂停执行的函数”。如果你把它理解成“就像生成器一样”,那么你就想对了。 执行结果: 用 为了简化并更好地标识异步IO,从Python 3.5开始引入了新的语法 请注意, 执行多个任务 结果: 获取返回值 结果: 执行多个任务获取返回值 Python 生成器和协程 标签:date cond stop https print 直接 dia setattr 结束 原文地址:https://www.cnblogs.com/51try-again/p/11074621.htmlPython3 迭代器与生成器
迭代器
>>> list = [1,2,3,4]
>>> it = iter(list) # 创建迭代器对象
>>> next(it) # 输出迭代器的下一个元素
1
>>> next(it)
2
>>>
>>> list = [‘a‘, ‘b‘, ‘c‘, ‘d‘]
>>> it = iter(list) # 创建迭代器对象
>>> for x in it:
print(x, end=" ")
a b c d
>>>
>>> lst = [2,6,8,9]
>>> it = iter(lst) # 创建迭代器对象
>>>
>>> while True:
try:
print(next(it))
except StopIteration:
break
2
6
8
9
>>>
创建一个迭代器
__iter__() 方法返回一个特殊的迭代器对象, 这个迭代器对象实现了 __next__() 方法并通过 StopIteration 异常标识迭代的完成。
__next__() 方法(Python 2 里是 next())会返回下一个迭代器对象。
class Counter:
def __iter__(self):
self.a = 1
return self
def __next__(self):
x = self.a
self.a += 1
return x
myclass = Counter()
myiter = iter(myclass)
print(next(myiter))
print(next(myiter))
print(next(myiter))
print(next(myiter))
print(next(myiter))
# 执行输出结果为:
1
2
3
4
5
StopIteration
>>> str1 = "Python"
>>> strObj = str1.__iter__()
>>> strObj.__next__()
‘P‘
>>> strObj.__next__()
‘y‘
>>> strObj.__next__()
‘t‘
>>> strObj.__next__()
‘h‘
>>> strObj.__next__()
‘o‘
>>> strObj.__next__()
‘n‘
>>> strObj.__next__()
Traceback (most recent call last):
File "
>>> tup = (1,2,3)
>>> type(tup)
‘__getnewargs__‘, ‘__gt__‘, ‘__hash__‘, ‘__init__‘, ‘__init_subclass__‘, ‘__iter__‘, ‘__le__‘, ‘__len__‘, ‘__lt__‘, ‘__mul__‘, ‘__ne__‘, ‘__new__‘,
‘__reduce__‘, ‘__reduce_ex__‘, ‘__repr__‘, ‘__rmul__‘, ‘__setattr__‘, ‘__sizeof__‘, ‘__str__‘, ‘__subclasshook__‘, ‘count‘, ‘index‘]
>>> print(‘__iter__‘ in dir(tup))
True
>>>
>>> dic = {1:‘dict‘, 2:‘str‘, 3:‘list‘, 4:‘tuple‘, 5:‘set‘, 6:‘range()‘,7:‘flie handler‘}
>>> isinstance(dic, Iterable)
True
>>> isinstance(dic, Iterator)
False
>>>
>>> ran = range(6)
>>> type(ran)
生成器
return返回后,函数状态终止,而yield会保存当前函数的执行状态,在返回后,函数又回到之前保存的状态继续执行。
>>> def fib(max): # 生成器函数 - 斐波那契
a, b, n = 0, 1, 0
while n >> f = fib(6) # 调用 fab(5) 不会执行 fab 函数,而是返回一个 iterable 对象!
>>> f # Python 解释器会将其视为一个 generator
>>> import numbers
>>> def gen_sum():
total = 0
while True:
num = yield
if isinstance(num, numbers.Integral):
total += num
print(‘total: ‘, total)
elif num is None:
break
return total
>>> g = gen_sum()
>>> g
yield from关键字
>>> def func():
lst = [‘str‘, ‘tuple‘, ‘list‘, ‘dict‘, ‘set‘]
yield lst
>>> gen = func()
>>> next(gen)
[‘str‘, ‘tuple‘, ‘list‘, ‘dict‘, ‘set‘]
>>> for i in gen:
print(i)
>>> # yield from 将一个可迭代对象变成一个迭代器返回
>>> def func2():
lst = [‘str‘, ‘tuple‘, ‘list‘, ‘dict‘, ‘set‘]
yield from lst
>>> gen2 = func2()
>>> next(gen2)
‘str‘
>>> next(gen2)
‘tuple‘
>>> for i in gen2:
print(i)
list
dict
set
>>>
>>> lst = [‘H‘,‘e‘,‘l‘]
>>> dic = {‘l‘:‘vvvvv‘,‘o‘:‘eeeee‘}
>>> str1 = ‘Python‘
>>>
>>> def yield_gen():
for i in lst:
yield i
for j in dic:
yield j
for k in str1:
yield k
>>> for item in yield_gen():
print(item, end=‘‘)
HelloPython
>>>
>>> l = [‘H‘,‘e‘,‘l‘]
>>> d = {‘l‘:‘xxxxx‘,‘o‘:‘ooooo‘}
>>> s = ‘Java‘
>>>
>>> def yield_from_gen():
yield from l
yield from d
yield from s
>>> for item in yield_from_gen():
print(item, end=‘‘)
HelloJava
>>>
为什么使用生成器
协程
使用yield实现协程
#基于yield实现异步
def consumer():
‘‘‘任务1:接收数据,处理数据‘‘‘
while True:
x=yield
def producer():
‘‘‘任务2:生产数据‘‘‘
g=consumer()
next(g)
for i in range(10000000):
g.send(i)
producer()
使用yield from实现的协程
import datetime
import heapq # 堆模块
import time
class Task:
def __init__(self, wait_until, coro):
self.coro = coro
self.waiting_until = wait_until
def __eq__(self, other):
return self.waiting_until == other.waiting_until
def __lt__(self, other):
return self.waiting_until
A waiting 0 seconds before starting countdown
before yield wait_until
B waiting 2 seconds before starting countdown
before yield wait_until
C waiting 1 seconds before starting countdown
before yield wait_until
**************************************************
after yield wait_until
A starting after waiting 0:00:00
A T-minus 5
before yield wait_until
--------------------------------------------------
**************************************************
after yield wait_until
C starting after waiting 0:00:01.001511
C T-minus 4
before yield wait_until
--------------------------------------------------
**************************************************
after yield wait_until
A T-minus 4
before yield wait_until
--------------------------------------------------
**************************************************
after yield wait_until
B starting after waiting 0:00:02.000894
B T-minus 3
before yield wait_until
--------------------------------------------------
**************************************************
after yield wait_until
C T-minus 3
before yield wait_until
--------------------------------------------------
**************************************************
after yield wait_until
A T-minus 3
before yield wait_until
--------------------------------------------------
**************************************************
after yield wait_until
B T-minus 2
before yield wait_until
--------------------------------------------------
**************************************************
after yield wait_until
C T-minus 2
before yield wait_until
--------------------------------------------------
**************************************************
after yield wait_until
A T-minus 2
before yield wait_until
--------------------------------------------------
**************************************************
after yield wait_until
B T-minus 1
before yield wait_until
--------------------------------------------------
**************************************************
after yield wait_until
C T-minus 1
before yield wait_until
--------------------------------------------------
**************************************************
after yield wait_until
A T-minus 1
before yield wait_until
--------------------------------------------------
**************************************************
after yield wait_until
B lift-off!
**************************************************
after yield wait_until
C lift-off!
**************************************************
after yield wait_until
A lift-off!
Total elapsed time is 0:00:05.005168
asyncio模块
asyncio
是Python 3.4版本引入的标准库,直接内置了对异步IO的支持。asyncio
提供的@asyncio.coroutine
可以把一个generator标记为coroutine类型,然后在coroutine内部用yield from
调用另一个coroutine实现异步操作。 asyncio
的编程模型就是一个消息循环。我们从asyncio
模块中直接获取一个EventLoop
的引用,然后把需要执行的协程扔到EventLoop
中执行,就实现了异步IO。coroutine+yield from
import asyncio
@asyncio.coroutine
def hello():
print("Nice to learn asyncio.coroutine!")
# 异步调用asyncio.sleep(1):
r = yield from asyncio.sleep(1)
print("Nice to learn asyncio.coroutine again !")
# 获取EventLoop:
loop = asyncio.get_event_loop()
# 执行coroutine
loop.run_until_complete(hello())
loop.close()
Nice to learn asyncio.coroutine !
Nice to learn asyncio.coroutine again !
async
和await
,可以让coroutine的代码更简洁易读。async
和 await
是针对coroutine的新语法,要使用新的语法,只需要做两步简单的替换:
@asyncio.coroutine
替换为async
;yield from
替换为await
。async+await
在协程函数中,可以通过await语法来挂起自身的协程,并等待另一个协程完成直到返回结果:
import asyncio
async def hello():
print("Nice to learn asyncio.coroutine!")
# 异步调用asyncio.sleep(1):
await asyncio.sleep(1)
print("Nice to learn asyncio.coroutine again !")
# 获取EventLoop:
loop = asyncio.get_event_loop()
# 执行coroutine
loop.run_until_complete(hello())
loop.close()
import threading
import asyncio
async def hello():
print(‘Hello Python! (%s)‘ % threading.currentThread())
await asyncio.sleep(1)
print(‘Hello Python again! (%s)‘ % threading.currentThread())
loop = asyncio.get_event_loop()
tasks = [hello(), hello()]
loop.run_until_complete(asyncio.wait(tasks))
loop.close()
Hello Python! (<_mainthread started>)
Hello Python! (<_mainthread started>)
Hello Python again! (<_mainthread started>)
Hello Python again! (<_mainthread started>)
import threading
import asyncio
async def hello():
print(‘Hello Python! (%s)‘ % threading.currentThread())
await asyncio.sleep(1)
print(‘Hello Python again! (%s)‘ % threading.currentThread())
return "It‘s done"
loop = asyncio.get_event_loop()
task = loop.create_task(hello())
loop.run_until_complete(task)
ret = task.result()
print(ret)
Hello Python! (<_mainthread started>)
Hello Python again! (<_mainthread started>)
It‘s done
import threading
import asyncio
async def hello(seq):
print(‘Hello Python! (%s)‘ % threading.currentThread())
await asyncio.sleep(1)
print(‘Hello Python again! (%s)‘ % threading.currentThread())
return "It‘s done", seq
loop = asyncio.get_event_loop()
task1 = loop.create_task(hello(2))
task2 = loop.create_task(hello(1))
task_list = [task1, task2]
tasks = asyncio.wait(task_list)
loop.run_until_complete(tasks)
for t in task_list:
print(t.result())
结果:
Hello Python! (<_mainthread started>)
Hello Python! (<_mainthread started>)
Hello Python again! (<_mainthread started>)
Hello Python again! (<_mainthread started>)
("It‘s done", 2)
("It‘s done", 1)