列表推导与生成器表达式
当我们创建了一个列表的时候,就创建了一个可以迭代的对象:
>>> squares=[n*n for n in range(3)] >>> for i in squares: print i 0 1 4
而生成器表达式不同,它执行的计算与列表包含相同,但会迭代的生成结果。它的语法与列表推导一样,只是要用小括号来代替中括号:
>>> squares=(n*n for n in range(3)) >>> for i in squares: print i 0 1 4
那么,还有没有其它方法来产生生成器呢?
例子:斐波那契数列
例如有个需求,要生成斐波那契数列的前10位,我们可以这样写:
def fib(n): result=[] a=1 b=1 result.append(a) for i in range(n-1): a,b=b,a+b result.append(a) return result if __name__=='__main__': print fib(10)
这样,需求就变成了:写一个可以生成可迭代对象的函数,或者说,不要让函数一次返回全部的值,而是一次返回一个值。
这好像与我们的常识相违背,当我们调用一个普通的Python函数时,一般是从函数的第一行代码开始执行,结束于return语句、异常或者函数结束(可以看作隐式的返回None):
def fib(n): a=1 b=1 for i in range(n-1): a,b=b,a+b return a if __name__=='__main__': print fib(10) >>> 1 #返回第一个值时就卡住了
def fib(n): a=1 yield a b=1 for i in range(n-1): a,b=b,a+b yield a if __name__=='__main__': for i in fib(10): print i >>> 1 1 2 3 5 8 13 21 34
生成器Generator
python中生成器的定义很简单,使用了yield关键字的函数就可以称之为生成器,它生成一个值的序列:
def countdown(n): while n>0: yield n n-=1 if __name__=='__main__': for i in countdown(10): print i
>>> c=countdown(10) >>> c.next() 10 >>> c.next() 9
next()不能无限执行,当迭代结束时,会抛出StopIteration异常。迭代未结束时,如果你想结束生成器,可以使用close()方法。
>>> c.next() 1 >>> c.next() StopIteration >>> c=countdown(10) >>> c.next() 10 >>> c.close() >>> c.next() StopIteration
yield语句还有更给力的功能,作为一个语句出现在赋值运算符的右边,接受一个值,或同时生成一个值并接受一个值。
def recv(): print 'Ready' while True: n=yield print 'Go %s'%n >>> c=recv() >>> c.next() Ready >>> c.send(1) Go 1 >>> c.send(2) Go 2
协程的运行一般是无限期的,使用方法close()可以显式的关闭它。
如果yield表达式中提供了值,协程可以使用yield语句同时接收和发出返回值。
def split_line(): print 'ready to split' result=None while True: line=yield result result=line.split() >>> s=split_line() >>> s.next() ready to split >>> s.send('1 2 3') ['1', '2', '3'] >>> s.send('a b c') ['a', 'b', 'c']
如果你想用send()方法来开启协程的执行,必须先send一个None值,因为这时候是没有yield语句来接受值的,否则就会抛出异常。
>>> s=split_line() >>> s.send('1 2 3') TypeError: can't send non-None value to a just-started generator >>> s=split_line() >>> s.send(None) ready to split
使用生成器与协程
乍看之下,如何使用生成器和协程解决实际问题似乎并不明显。但在解决系统、网络和分布式计算方面的某些问题时,生成器和协程特别有用。实际上,yield已经成为Python最强大的关键字之一。
比如,要建立一个处理文件的管道:
import os,sys def default_next(func): def start(*args,**kwargs): f=func(*args,**kwargs) f.next() return f return start @default_next def find_files(target): topdir=yield while True: for path,dirname,filelist in os.walk(topdir): for filename in filelist: target.send(os.path.join(path,filename))@default_next def opener(target): while True: name=yield f=open(name) target.send(f) @default_next def catch(target): while True: f=yield for line in f: target.send(line) @default_next def printer(): while True: line=yield print line
finder=find_files(opener(catch(printer()))) finder.send(toppath)
总之,生成器的功能非常强大。协程可以用于实现某种形式的并发。在某些类型的应用程序中,可以用一个任务调度器和一些生成器或协程实现协作式用户空间多线程,即greenlet。yield的威力将在协程,协同式多任务处理(cooperative multitasking),以及异步IO中得到真正的体现。
本文向大家介绍Python中的闭包详细介绍和实例,包括了Python中的闭包详细介绍和实例的使用技巧和注意事项,需要的朋友参考一下 一、闭包 来自wiki: 闭包(Closure)是词法闭包(Lexical Closure)的简称,是引用了自由变量的函数。这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外。所以,有另一种说法认为闭包是由函数和与其相关的引用环境组合而成的实
本文向大家介绍详细介绍Python中的偏函数,包括了详细介绍Python中的偏函数的使用技巧和注意事项,需要的朋友参考一下 Python的functools模块提供了很多有用的功能,其中一个就是偏函数(Partial function)。要注意,这里的偏函数和数学意义上的偏函数不一样。 在介绍函数参数的时候,我们讲到,通过设定参数的默认值,可以降低函数调用的难度。而偏函数也可以做到这一点。举例如下
本文向大家介绍Python中的tuple元组详细介绍,包括了Python中的tuple元组详细介绍的使用技巧和注意事项,需要的朋友参考一下 Tuple 是不可变 list。 一旦创建了一个 tuple 就不能以任何方式改变它。 Tuple 与 list 的相同之处 定义 tuple 与定义 list 的方式相同, 除了整个元素集是用小括号包围的而不是方括号。 Tuple 的元素与 list 一样按
本文向大家介绍Python 模块EasyGui详细介绍,包括了Python 模块EasyGui详细介绍的使用技巧和注意事项,需要的朋友参考一下 Python 模块EasyGui详细介绍 前言: 在Windows想用Python开发一些简单的界面,所以找到了很容易上手的EasyGui库。下面就分享一下简单的使用吧。 参考的链接:官网Tutorial 接下来,我将从简单,到复杂一点点的演示如何使用这个
问题内容: 我正在尝试在给定函数f和初始值x的情况下生成无穷无尽的结果流,因此第一个调用应给出初始值,第二个调用应给出f(x),第三个调用为f(x2),而x2是前一个f(x)的结果,依此类推。 我想出了什么: 这似乎不起作用。有任何想法吗?(我不能在代码中使用yield)。我也不能使用超过1行代码来解决此问题。任何帮助,将不胜感激。 还请注意,在以前的版本中。我被要求使用产量。没问题: 这很好。但
本文向大家介绍详细介绍Python的鸭子类型,包括了详细介绍Python的鸭子类型的使用技巧和注意事项,需要的朋友参考一下 鸭子类型基本定义 首先Python不支持多态,也不用支持多态,python是一种多态语言,崇尚鸭子类型。 以下是维基百科中对鸭子类型得论述: 在程序设计中,鸭子类型(英语:duck typing)是动态类型的一种风格。在这种风格中,一个对象有效的语义,不是由继承自特定的类或实