自己做网站的网址,信息门户,360网站上做宣传要多少钱,wordpress本地做好如何改站点地址前言Python生成器(generator)并不是一个晦涩难懂的概念。相比于MetaClass和Closure等概念#xff0c;其较为容易理解和掌握。但相对于程序结构#xff1a;顺序、循环和分支而言其又不是特别的直观。无论学习任何的东西#xff0c;概念都是非常重要的。正确树立并掌握一些基础…前言Python生成器(generator)并不是一个晦涩难懂的概念。相比于MetaClass和Closure等概念其较为容易理解和掌握。但相对于程序结构顺序、循环和分支而言其又不是特别的直观。无论学习任何的东西概念都是非常重要的。正确树立并掌握一些基础的概念是灵活和合理运用的前提本文将以一种通俗易懂的方式介绍一下generator和yield表达式。1. Iterator与Iterable首先明白两点Iterator(迭代器)是可迭代对象;可迭代对象并不一定是Iterator;比较常见的数据类型list、tuple、dict等都是可迭代的属于collections.Iterable类型迭代器不仅可迭代还可以被内置函数next调用属于collections.Iterator类型迭代器是特殊的可迭代对象是可迭代对象的一个子集。将要介绍的gererator(生成器)是types.GeneratorType类型也是collections.Iterator类型。也就是说生成器是迭代器可被next调用也可迭代。三者的包含关系(可迭代(迭代器(生成器)))迭代器可用next()函数访问的对象生成器生成器表达式和生成器函数2. Python生成器python有两种类型的生成器生成器表达式和生成器函数。由于生成器可迭代并且是iterator因此可以通过for和next进行遍历。2.1 生成器表达式把列表生成式的[]改成()便得到生成器表达式。 gen (i i for i in xrange(10)) gen at 0x0000000003A2DAB0 type(gen) isinstance(gen, types.GeneratorType) and isinstance(gen, collections.Iterator) and isinstance(gen, collections.Iterable)True2.2 生成器函数python函数定义中有关键字yield该函数便是一个生成器函数函数调用返回的是一个generator.def yield_func():for i in xrange(3):yield igen_func yield_func()for yield_val in gen_func:print yield_val生成器函数每次执行到yield便会返回但与普通函数不同的是yield返回时会保留当前函数的执行状态再次被调用时可以从中断的地方继续执行。2.3 next与send通过for和next可以遍历生成器而send则可以用于向生成器函数发送消息。def yield_func():for i in xrange(1, 3):x yield iprint yield_func,xgen_func yield_func()print iter result: %d % next(gen_func)print iter result: %d % gen_func.send(100)结果iter result: 1yield_func 100iter result: 2简单分析一下执行过程line_no 5 调用生成器函数yield_func得到函数生成器gen_funcline_no 6 使用next调用gen_func此时才真正的开始执行yield_func定义的代码line_no 3 执行到yield i函数yield_func暂停执行并返回当前i的值1.line_no 6 next(gen_func)得到函数yield_func执行到yield i返回的值1输出结果iter result: 1line_no 7 执行gen_func.send(100);line_no 3 函数yield_func继续执行并将调用者send的值100赋值给x;line_no 4 输出调用者send接收到的值line_no 3 执行到yield i函数yield_func暂停执行并返回当前i的值2.line_no 7 执行gen_func.send(100)得到函数yield_func运行到yield i返回的值2输出结果iter result: 2如果在上面代码后面再加一行print iter result: %d % next(gen_func)结果iter result: 1yield_func 100iter result: 2yield_func NoneFile G:\Cnblogs\Alpha Panda\Main.py, line 22, in print iter result: %d % next(gen_func)StopIterationyield_func只会产生2个yield但是我们迭代调用了3次会抛出异常StopIteration。next和send均会触发生成器函数的执行使用for遍历生成器函数时不要用send。原因后面解释。2.4 生成器返回值使用了yield的函数严格来讲已经不是一个函数而是一个生成器。因此函数中yield和return是不能同时出现的。SyntaxError: return with argument inside generator生成器只能通过yield将每次调用的结果返回给调用者。2.5 可迭代对象转成迭代器list、tuple、dict等可迭代但不是迭代器的对象可通过内置函数iter转化为iterator便可以通过next进行遍历这样的好处是可以统一使用next遍历所有的可迭代对象tup (1,2,3)for ele in tup:print ele ele上面的代码等价于tup_iterator iter(tup)while True:try:ele next(tup_iterator)except StopIteration:breakprint ele elefor循环使用next遍历一个迭代器混合使用send可能会导致混乱的遍历流程。其实到这里生成器相关的概念基本已经介绍完成了自己动手过一遍应该能弄明白了。为了更加深刻的体会生成器下面我们在往前走一步。3. range与xrange在Python 2中这两个比较常用看一下两者的区别range为一个内置函数xrange是一个类前者返回一个list后者返回一个可迭代对象后者遍历操作快于前者且占用更少内存这里xrange有点类似于上面介绍的生成器表达式虽然xrange返回的并不是生成器但两者均返回并不包含全部结果可迭代对象。3.1 自定义xrange的Iterator版本作为一个iterator:The iterator objects themselves are required to support the following two methods, which together form the iterator protocol:iterator.__iter__()Return the iterator object itself. This is required to allow both containers and iterators to be used with the for and in statements. This method corresponds to the tp_iter slot of the type structure for Python objects in the Python/C API.iterator.next()Return the next item from the container. If there are no further items, raise the StopIteration exception. This method corresponds to the tp_iternext slot of the type structure for Python objects in the Python/C API.下面我们自定义class my_xrange:class my_xrange(object):def __init__(self, start, stop None, step 1): 仅仅为了演示假设start, stop 和 step 均为正整数 self._start 0 if stop is None else startself._stop start if stop is None else stopself._step stepself._cur_val self._startdef __iter__(self):return selfdef next(self):if self._start self._cur_val self._stop:cur_val self._cur_valself._cur_val self._stepreturn cur_valraise StopIteration测试结果import collectionsmyxrange my_xrange(0, 10, 3)res []for val in myxrange:res.append(val)print res range(0, 10, 3) # Trueprint isinstance(myxrange, collections.Iterator) # Trueprint isinstance(myxrange, types.GeneratorType) # False3.2 使用函数生成器下面使用函数生成器定义一个generator版的xrange。def xrange_func(start, stop, step 1): 仅仅为了演示假设start, stop 和 step 均为正整数 cur_val startwhile start cur_val and cur_val stop:yield cur_valcur_val stepisinstance(myxrange, collections.Iterator) and isinstance(myxrange, types.GeneratorType) is True上面两个自定义xrange版本的例子均说明生成器以及迭代器保留数列生成过程的状态每次只计算一个值并返回。这样只要占用很少的内存即可表示一个很大的序列。4. 应用不管是迭代器还是生成器对于有大量有规律的数据产生并需要遍历访问的情景均适用占用内存少而且遍历的速度快。其中一个较为经典的应用为斐波那契数列(Fibonacci sequence)。这里以os.walk遍历目录为例来说明yield的应用。如果我们需要遍历一个根目录下的所有文件并根据需要进行增删改查。可能会遇到下列的问题预先遍历且缓存结果但是目录下文件可能很多而且会动态改变如果不缓存多个地方可能会频繁的需要访问这一结果导致效率低下。这时候可以使用yield定义一个生成器函数。def get_all_dir_files(target_dir):for root, dirs, files in os.walk(target_dir):for file in files:file_path os.path.join(root, file)yield os.path.realpath(file_path)def file_factory(file): do something target_dir ./all_files get_all_dir_files(target_dir)for file in all_files:file_factory(file)限于篇幅就先介绍到这里希望本文能让你对生成器有一个新的认识。,文中通过示例代码介绍的非常详细对大家的学习或者工作具有一定的参考学习价值