python迭代器与生成器及yield

摘要:
python中的迭代对象包括:sequence:string、list、tuple non-sequence:dictionary、file用户定义类:用户定义类__iter_()或__getitem_()方法2的对象。迭代器:在python中,如果对象具有__iter__()方法和__next__()方法,则该对象称为迭代器;Including_iter_()方法是使对象能够使用for…in_next_进行迭代。()方法允许对象通过next(实例名)访问下一个元素。这两个方法必须同时存在才能称为迭代器。

一、迭代器(itertor)

1.可迭代:

在Python中如果一个对象有__iter__()方法或__getitem__()方法,则称这个对象是可迭代的(iterable)。
其中__iter__()方法的作用是让对象可以用“for ... in...”方式来循环遍历,_getitem_()方法是让对象可以通过“实例名[index]”的方式访问实例中的元素。换句话说,两个条件只要满足一条,就可以说对象是可迭代的。

python中的可迭代对象有:

(1)序列:字符串、列表、元组
(2)非序列:字典、文件
(3)自定义类:用户自定义的类实现了__iter__()或__getitem__()方法的对象

2.迭代器:

在Python中如果一个对象有__iter__()方法和__next__()方法,则称这个对象是迭代器(Iterator);其中__iter__()方法是让对象可以用for ... in ...循环遍历,_next_()方法是让对象可以通过next(实例名)访问下一个元素。这两个方法必须同时具备,才能称之为迭代器。

列表List、元组Tuple、字典Dictionary、字符串String等数据类型虽然是可迭代的,但都不是迭代器,因为他们都没有__next__()方法。

from collections import Iterable,Iterator

# 字符串、列表、元组、集合、字典都是可迭代对象
print(isinstance('123',Iterable))   # True
print(isinstance([1,2,3],Iterable))   # True
print(isinstance((1,2,3),Iterable))   # True
print(isinstance({1,2,3},Iterable))   # True
print(isinstance({"one":1,"two":2,"three":3},Iterable))   # True

# 字符串、列表、元组、集合、字典都不是迭代器
print(isinstance('123',Iterator))   # False
print(isinstance([1,2,3],Iterator))   # False
print(isinstance((1,2,3),Iterator))   # False
print(isinstance({1,2,3},Iterator))   # False
print(isinstance({"one":1,"two":2,"three":3},Iterator))   # False

3.总结:

  • 迭代器都是可迭代的,但可迭代的不一定是迭代器;可用for ... in ...循环的都是可迭代的,可用next()遍历的才是迭代器;
  • next()是单向的,一次只获取一个元素,获取到最后一个元素后停止;
  • 在可迭代的对象中提前存储了所有的元素,而迭代器是惰性的,只有迭代到了某个元素,该元素才会生成。

4.延迟计算或惰性求值 (Lazy evaluation)

迭代器不要求你事先准备好整个迭代过程中所有的元素。仅仅是在迭代至某个元素时才计算该元素,而在这之前或之后,元素可以不存在或者被销毁。这个特点使得它特别适合用于遍历一些巨大的或是无限的集合。

迭代之前元素可以是不存在的,迭代之后元素也可以被销毁,因此迭代器在处理大量数据甚至无限数据时具有加载数据快、占用内存小等优势。

5.创建迭代器:

(1)使用内建的工厂函数iter(iterable[, sentinel])

iter()函数只传入一个参数时,参数必须为可迭代对象;当使用第二个参数sentinel(哨兵)时,第一个参数必须是一个可调用对象。

当有第二个参数sentinel传入时,参数iterable应是一个可调用对象,这时候迭代器它会重复地调用第一个参数,当枚举到的值等于哨兵时,就会抛出异常StopIteration。

s = "abcdefgh"
iter1 = iter(s)
print(isinstance(iter1,Iterator))   # True
使用第二个参数的情况此处不描述了

(2)自己写类,其中实现__iter__()方法和__next__()方法

在__next__()方法中必须对迭代进行检查,超出范围则触发 StopIteration 异常。注意避免死循环。

class MyIterator(object):
    def __init__(self, data):
        self.data = data
    def __iter__(self):
       return self
    def __next__(self):
        if self.data <= 20:
           self.data += 2
            return self.data
        else:
           raise StopIteration

myIter = MyIterator(5)

print(isinstance(myIter,Iterator))  # True
print(next(myIter))     # 7
print(next(myIter))     # 9
print(next(myIter))     # 11
...

二、生成器(generator)

在Python中,不会一次性的生成所有的值,而是调用一次,生成一个值,再调用一次,生成下一个值。
即生成器不会把结果保存在一个系列中,而是保存生成器的状态,在每次进行迭代时返回一个值,直到遇到StopIteration异常时结束。

创建生成器的两种基本方法

1.生成器表达式:

通列表解析语法,在写列表生成式时,把[]换成()即可

实例:

# 列表生成式
>>> l = [i for i in range(5)]
>>> l
[0, 1, 2, 3, 4]

# 生成器表达式
>>> g = (i for i in range(5))
>>> g
<generator object <genexpr> at 0x000001A5108D5938>
>>> next(g)
0
>>> next(g)
1
>>> next(g)
2

2.生成器函数

在 Python 中,使用了(一个或多个)yield语句的函数,就叫做生成器函数。

解释器处理这种函数定义的时候将创建特殊的生成器函数对象,而不是普通的函数对象。调用生成器函数的时候,返回值就是一个生成器对象。它只能用于迭代操作,更简单点理解生成器就是一种迭代器。
在调用生成器运行的过程中,每次遇到 yield 时函数会暂停并保存当前所有的运行信息,返回 yield 的值, 并在下一次执行 next() 方法时从当前位置继续运行。

实例:

# 实现的斐波那契数列
def fib_gen(n):
    f0, f1 = 0, 1
    for n in range(n):
        yield f0
        f0, f1 = f1, f0+f1

print(fib_gen(5))   # <generator object fib_gen at 0x0000023A5BB78830>

g = fib_gen(6)  # g就是一个生成器对象(也是一种迭代器)
print(next(g))  # 0
print(next(g))  # 1
print(next(g))  # 1
print(next(g))  # 2

# 生成器是包含有__iter__()和__next__()方法的,所以可以直接使用for来迭代
for x in fib_gen(5):
    print(x, end=', ')
# 0, 1, 1, 2, 3, 

2.1.yield 与 return

在一个生成器中,如果没有return,则默认执行到函数完毕时返回StopIteration异常。

>>> def gen():
...     for i in range(2)
...         yield 1
...
>>> g=gen()
>>> next(g)    #第一次调用next(g)时,会在执行完yield语句后挂起,此时程序并没有执行结束。
0
>>> next(g)    #第二次调用next(g),同样会在执行完yield语句后挂起,此时程序并没有执行结束。
1
>>> next(g)    #程序试图从yield语句的下一条语句开始执行,发现已经到了结尾,所以抛出StopIteration异常。
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration
>>>

生成器函数有return,如果return语句没有返回值,则直接抛出StopIteration异常。如果return语句有返回值,那么这个返回值会成为抛出StopIteration异常的一个说明。

>>> def ff():
...    for i in range(2):
...        yield i
...    return 'i finished.'
...
>>> g = ff()
>>> next(g)
0
>>> next(g)
1
>>> next(g)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration: i finished.

2.2.yield from语法

yield from 是在Python3.3才出现的语法。所以这个特性在Python2中是没有的。

yield from 后面需要加的是可迭代对象,它可以是普通的可迭代对象,也可以是迭代器,甚至是生成器。

yield from 主要用于生成器的嵌套,重点是帮我们自动处理内外层之间的异常问题。

这种用法参考博客:深入理解yield from语法

3.生成器支持的方法

**① **generator.send(expr)

启动新生成器或唤醒处于挂起状态的生成器,把参数expr的值传送给它,使之成为当时挂起的那个yield表达式的值。

本操作导致generator继续执行到下一个yield表达式(或者语句),返回yield值。对新生成器调用send时参数只能是None,因为当时不存在等待值的yield表达式。

def gen():
    value=0
    while True:
        receive=yield value
        if receive=='e':
            break
        value = 'i got: %s' % receive

g=gen()
print(g.send(None))   # 这里用next(g)也是一样
print(g.send('aaa'))
print(g.send(3))
print(g.send('e'))

执行流程:

  • 通过g.send(None)或者next(g)可以启动生成器函数,并执行到第一个yield语句结束的位置,yield value会输出初始值0。此时,执行完了yield语句,但是没有给receive赋值,因为执行完yield程序就处于挂起状态了,还没有来得急给receive赋值。

  • 通过g.send('aaa'),会传入值aaa作为yield表达式的值,然后继续执行程序,此时把yield表达式的值赋值给receive,然后计算出value的值,并回到while头部,执行yield value语句又暂停。此时yield value会输出"got: aaa",然后挂起。

  • 通过g.send(3),会重复第2步,最后输出结果为"got: 3"

  • 当我们g.send('e')时,程序会执行break然后推出循环,最后整个函数执行完毕,所以会得到StopIteration异常。

最后的执行结果如下:

0
i got: aaa
  File "生成器.py", line 104, in <module>
i got: 3
    print(g.send('e'))
StopIteration

② :generator.close()

手动关闭生成器函数,如果继续调用next()获取下一个值会直接抛出StopIteration异常。

def gen():
    value=0
    while True:
        receive=yield value
        if receive=='e':
            break
        value = 'i got: %s' % receive

g=gen()
print(next(g))
g.close()
print(next(g))  # 继续调用抛出StopIteration异常

③ :generator.throw(type[,value[,traceback]])

启动新生成器或唤醒处于挂起状态的生成器,在当时挂起的yield表达式(语句)处抛出type类型的异常,该异常可以附带value作为参数说明,还可以有相应的traceback对象。

这个调用也返回generator生成器的下一个值,如果此时生成器退出或没有产生yield值,会抛出StopIteration异常。简单说,会抛出异常并结束程序,或者消耗掉一个yield值,或者在没有下一个yield的时候直接进行到程序的结尾。

def gen():
    while True:
        try:
            yield 'normal value1'
            yield 'normal value 2'
            print('here')
        except ValueError:
            print('ValueError : ...... ')
        except TypeError as e:
            print('TypeError : ',e)
            break

g=gen()
print(next(g))
print(g.throw(ValueError))
print(next(g))
print(g.throw(TypeError,'i raised a TypeError'))

执行结果:

normal value1
Traceback (most recent call last):
ValueError : ...... 
normal value1
  File "生成器.py", line 121, in <module>
normal value 2
    print(g.throw(TypeError,'i raised a TypeError'))
TypeError :  i raised a TypeError
StopIteration

免责声明:文章转载自《python迭代器与生成器及yield》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇sqlite报SQLITE_LOCKED "Database table is locked"Tomcat关闭日志catalina.out下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

C++面试

https://blog.csdn.net/weixin_44363885/article/details/99567746 这一行是个 贼鸡巴重要的链接!!!   很好的总结 我直接复制到下面了: 社招:社招的同学,无论是1-3年经验,还是中途转行,都可参考。写简历必须有针对性,以后台开发为例,请去拉勾网 / 猎聘 / 智联招聘等网站,多看看后台开发的J...

使用 SCons 轻松建造程序

原文:http://www.ibm.com/developerworks/cn/linux/l-cn-scons/index.html 参考:http://www.flatws.cn/article/program/python/2011-06-02/28680.html 前言 make 这个工具自上个世纪 70 年代 Stuart Feldman 在贝尔...

《深入实践C++模板编程》之二——模板类

1、类的模板的使用 类,由于没有参数,所以没有模板实参推导机制。 1 #include <stdexcept> 2 3 template<typename T> class my_stack; 4 5 template<typename T> 6 class list_node 7 {...

windows+django3.1+ASGI+nginx部署

# 了解CGI CGI(通用网关接口, Common Gateway Interface/CGI),定义客户端与Web服务器的交流方式的一个程序。 #  什么是WSGI PythonWeb服务器网关接口(Python Web Server Gateway Interface,缩写为WSGI)是Python应用程序或框架和Web服务器之间的一种接口,已经被广...

利用pyinstaller打包加密Python项目

  最近用Python给媳妇写了两个小项目,给解决了她的每天重复的一些人工操作。媳妇很开心,但是问题来了,她是个Python小白,对她来说,需要安装配置Python环境和一大堆第三方模块是个麻烦事儿。而且后续把这些工作交接给别人的话,一是又需要重新安装Python环境,二是我辛苦给她写的源码就这样暴露了。   为了解决这个问题,于是就开始百度。果然Pyth...

python实现生成 json web token

Python 生成 JWT(json web token) 及 解析方式 jwt原理及概念博客:https://www.freebuf.com/articles/web/180874.html 推荐博客:https://zhuanlan.zhihu.com/p/86937325 JWT 的官方文档: https://jwt.io/introduction...