迭代器
迭代器只不过是一个实现迭代器协议的容器对象。它基于两个方法:
迭代器可以通过使用一个iter内建函数和一个序列来创建,示例如下。
生成器
Python引入的与生成器相关的最后一个特性是提供了与next方法调用的代码进行交互的功能。yield将变成一个表达式,而一个值可以通过名为send的新方法来传递,如下所示。
Output:
Please tell me your problems
Don't be so negative
Don't ask yourself too much questions
A that's good, go on
send的工作机制与next一样,但是yield将变成能够返回传入的值。因而,这个函数可以根据客户端代码来改变其行为。同时,还添加了throw和close两个函数,以完成该行为。它们将向生成器抛出一个错误:
throw 允许客户端代码传入要抛出的任何类型的异常;
close的工作方式是相同的,但是将会抛出一个特定的异常——GeneratorExit,在这种情况下,生成器函数必须再次抛出GeneratorExit或StopIteration异常。
finally部分在之前的版本是不允许使用的,它将捕获任何未被捕获的clise和throw调用,是完成清理工作的推荐方式。
协同程序
协同程序是可以挂起、回复,并且有多个进入点的函数。它们可以实现协同的多任务和管道机制。例如:每个协同程序将消费或生产的数据,然后暂停,直到其他数据被传递。
在Python中,协同程序的替代者是线程,它可以实现代码块之前的交互。但是因为它们表现出一种抢先式的风格,所以必须注意资源锁,而协同程序不需要。这样的代码可能变得相当复杂,难以创建和调试。但是生成器几乎就是协同程序,添加send、throw和close其初始的意图就是为该语言提供一种类似协同程序的特性。
使用multimask模块
在协同程序之间的写作,最经典的例子是接受来自多个客户的查询,并将每个查询委托给对此作出相应的新线程的服务器应用程序。
生成器表达式
itertools模块
islice:窗口迭代器
tee:往返式的迭代器
groupby:uniq迭代器
迭代器只不过是一个实现迭代器协议的容器对象。它基于两个方法:
- next 返回容器的写一个项目;
- __iter__ 返回迭代器本身。
迭代器可以通过使用一个iter内建函数和一个序列来创建,示例如下。
- >>> i = iter('abc')
- >>> i.next()
- 'a'
- >>> i.next()
- 'b'
- >>> i.next()
- 'c'
- >>> i.next()
- Traceback (most recent call last):
- File "<stdin>", line 1, in <module>
- StopIteration
引用
当序列遍历完时,将抛出一个StopIteration异常。这将使迭代器与循环兼容,因为它将捕获这个异常以停止循环。要创建定制的迭代器,可以编写一个具有next方法的类,只要该类能够提供返回迭代器实例的__iter__特殊方法。
- class MyIterator(object):
- def __init__(self, step):
- self.step = step
- def next(self):
- if self.step == 0:
- raise StopIteration
- self.step -= 1
- return self.step
- def __iter__(self):
- return self
- for el in MyIterator(4):
- print el
生成器
引用
生成器提供了一种出色的方法,使得需要返回一系列元素的函数所需的代码更加简单、高效。基于yield指令,可以暂停一个函数并返回中间结果。该函数将保存执行环境并且可以在必要时恢复。
- #!/usr/bin/env python
- #-*-coding:utf-8-*-
- def fibonacci():
- a, b = 0, 1
- while True:
- yield b
- a, b = b, a + b
- fib = fibonacci()
- print [fib.next() for i in range(10)]
- print map(lambda x,f = lambda x,f:f(x-1,f)+f(x-2,f) if x >1 else x:f(x,f),range(10))
Python引入的与生成器相关的最后一个特性是提供了与next方法调用的代码进行交互的功能。yield将变成一个表达式,而一个值可以通过名为send的新方法来传递,如下所示。
- def psychologist():
- print 'Please tell me your problems'
- while True:
- answer = (yield)
- if answer is not None:
- if answer.endswith('?'):
- print ("Don't ask yourself too much questions")
- elif 'good' in answer:
- print "A that's good, go on"
- elif 'bad' in answer:
- print "Don't be so negative"
- free = psychologist()
- free.next()
- free.send('I feel bad')
- free.send("?")
- free.send("ok then i should find what is good for me")
Output:
Please tell me your problems
Don't be so negative
Don't ask yourself too much questions
A that's good, go on
send的工作机制与next一样,但是yield将变成能够返回传入的值。因而,这个函数可以根据客户端代码来改变其行为。同时,还添加了throw和close两个函数,以完成该行为。它们将向生成器抛出一个错误:
throw 允许客户端代码传入要抛出的任何类型的异常;
close的工作方式是相同的,但是将会抛出一个特定的异常——GeneratorExit,在这种情况下,生成器函数必须再次抛出GeneratorExit或StopIteration异常。
- def my_generator():
- try:
- yield 'something'
- except ValueError:
- yield 'dealing with the exception'
- finally:
- print "ok let's clean"
- gen = my_generator()
- print gen.next()
- print gen.throw(ValueError('mean mean mean'))
- gen.close()
- print gen.next()
finally部分在之前的版本是不允许使用的,它将捕获任何未被捕获的clise和throw调用,是完成清理工作的推荐方式。
协同程序
协同程序是可以挂起、回复,并且有多个进入点的函数。它们可以实现协同的多任务和管道机制。例如:每个协同程序将消费或生产的数据,然后暂停,直到其他数据被传递。
在Python中,协同程序的替代者是线程,它可以实现代码块之前的交互。但是因为它们表现出一种抢先式的风格,所以必须注意资源锁,而协同程序不需要。这样的代码可能变得相当复杂,难以创建和调试。但是生成器几乎就是协同程序,添加send、throw和close其初始的意图就是为该语言提供一种类似协同程序的特性。
使用multimask模块
- #!/usr/bin/env python
- # -*- coding:utf-8 -*-
- import multitask
- def coroutine_1():
- for i in range(3):
- print 'c1'
- yield i
- def coroutine_2():
- for i in range(3):
- print 'c2'
- yield i
- multitask.add(coroutine_1())
- multitask.add(coroutine_2())
- multitask.run()
在协同程序之间的写作,最经典的例子是接受来自多个客户的查询,并将每个查询委托给对此作出相应的新线程的服务器应用程序。
- #!/usr/bin/env python
- # -*- coding:utf-8 -*-
- from __future__ import with_statement
- from contextlib import closing
- import socket
- import multitask
- def client_handler(sock):
- while closing(sock):
- while True:
- data = (yield multitask.recv(sock, 1024))
- if not data:
- break
- yield multitask.send(sock, data)
- def echo_server(hostname, port):
- addrinfo = socket.getaddrinfo(hostname, port, socket.AF_UNSPEC,socket.SOCK_STREAM)
- (family, socktype, proto, cannoname, sockaddr) = addrinfo[0]
- with closing(socket.socket(family,socktype,proto)) as sock:
- sock.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
- sock.bind(sockaddr)
- sock.listen(5)
- while True:
- multitask.add(client_handler((yield multitask.accept(sock))[0]))
- if __name__ == "__main__":
- import sys
- hostname = None
- port = 1111
- if len(sys.argv) > 1:
- hostname = sys.argv[1]
- if len(sys.argv) > 2:
- port = int(sys.argv[2])
- multitask.add(echo_server(hostname,port))
- try:
- multitask.run()
- except KeyboardInterrupt:
- pass
生成器表达式
- >>> iter = (x**2 for x in range(10) if x % 2 == 0)
- >>> for el in iter:
- ... print el
- …
- 0
- 4
- 16
- 36
- 64
itertools模块
islice:窗口迭代器
tee:往返式的迭代器
groupby:uniq迭代器
- #!/usr/bin/env python
- #-*-coding:utf-8-*-
- from itertools import group by
- def compress(data):
- return ((len(list(group)),name) for name,group in groupby(data))
- def decompress(data):
- return (car * size for size, car in data)
- print list(compress('get uuuuuuuuuuuuuuuup'))
- compressed = compress('get uuuuuuuuuuuuuuuup')
- print ''.join(decompress(compressed))