设为首页 加入收藏

TOP

Python-Day4 Python基础进阶之生成器/迭代器/装饰器/Json & pickle 数据序列化(一)
2017-09-30 17:40:05 】 浏览:7045
Tags:Python-Day4 Python 基础 进阶 成器 装饰 /Json pickle 数据 序列化

一、生成器

  通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器:generator。

要创建一个generator,有很多种方法。第一种方法很简单,只要把一个列表生成式的[]改成(),就创建了一个generator:

>>> L = [ x*2 for x in range(5)] >>> L [0, 2, 4, 6, 8] >>> g = ( x*2 for x in range(5) ) >>> g <generator object <genexpr> at 0x000000000321EF68>

  创建Lg的区别仅在于最外层的[]()L是一个list,而g是一个generator。我们可以直接打印出list的每一个元素,但我们怎么打印出generator的每一个元素呢?如果要一个一个打印出来,可以通过next()函数获得generator的下一个返回值:

>>> next(g) 0 >>> next(g) 2
>>> next(g) 4
>>> next(g) 6
>>> next(g) 8
>>> next(g) Traceback (most recent call last): File "<pyshell#11>", line 1, in <module> next(g) StopIteration >>> g <generator object <genexpr> at 0x000000000321EF68>
>>> g = ( x*2 for x in range(5) ) >>> for n in g: print(n) 0 2
4
6
8

  generator保存的是算法,每次调用next(g),就计算出g的下一个元素的值,直到计算到最后一个元素,没有更多的元素时,抛出StopIteration的错误。当然,这种不断调用next(g)实在是太变态了,正确的方法是使用for循环,因为generator也是可迭代对象。所以,我们创建了一个generator后,基本上永远不会调用next(),而是通过for循环来迭代它,并且不需要关心StopIteration的错误。

generator非常强大。如果推算的算法比较复杂,用类似列表生成式的for循环无法实现的时候,还可以用函数来实现。

比如,著名的斐波拉契数列(Fibonacci),除第一个和第二个数外,任意一个数都可由前两个数相加得到:

1, 1, 2, 3, 5, 8, 13, 21, 34, ...

斐波拉契数列用列表生成式写不出来,但是,用函数把它打印出来却很容易:

>>> def fib(max): n,a,b = 0,0,1
    while n<max: print(b) a,b =b,a+b n=n+1
    return 'done'

>>> fib(10) 1
1
2
3
5
8
13
21
34
55
'done'
'''仔细观察,可以看出,fib函数实际上是定义了斐波拉契数列的推算规则,可以从第一个元素开始,推算出后续任意的元素,这种逻辑其实非常类似generator。 也就是说,上面的函数和generator仅一步之遥。要把fib函数变成generator,只需要把print(b)改为yield b就可以了: '''
>>> def fib(max): n,a,b = 0,0,1
    while n<max: yield b a,b =b,a+b n=n+1
    return 'done'

>>> f=fib(5) >>> f <generator object fib at 0x000000000321EF68>

>>> print(next(f)) 1
>>> print(next(f)) 1
>>> print(next(f)) 2
>>> print(next(f)) 3
>>> print(next(f)) 5
>>> print(next(f)) Traceback (most recent call last): File "<pyshell#49>", line 1, in <module>
    print(next(f)) StopIteration: done

  在上面fib的例子,我们在循环过程中不断调用yield,就会不断中断。当然要给循环设置一个条件来退出循环,不然就会产生一个无限数列出来。同样的,把函数改成generator后,我们基本上从来不会用next()来获取下一个返回值,而是直接使用for循环来迭代:

>>> for n in fib(5): ... print(n) ... 1
1
2
3
5
''' 但是用for循环调用generator时,发现拿不到generator的return语句的返回值。如果想要拿到返回值,必须捕获StopIteration错误,返回值包含在StopIteration的value中: '''
>>> g=fib(5) >>> while True: try: x=next(g) print('g:',x) except StopIteration as e: print('Generator return value:', e.value) break g: 1 g: 2 g: 3 g: 5 g: 8 Generator return value: done

  通过yield实现在单线程的情况下实现并发运算的效果:(暂时保留)

二、迭代器

  迭代是Python最强大的功能之一,是访问集合元素的一种方式。迭代器是一个可以记住遍历的位置的对象。迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退。

以直接作用于for循环的数据类型有以下几种:

一类是集合数据类型,如listtupledictsetstr等;

一类是generator,包括生成器和带yield的generator function。

这些可以直接作用于for循环的对象统称为可迭代对象:Iterable

可以使用isinstance()判断一个对象是否是Iterable对象:

>>> from collections import Iterable >>> isinstance([], Itera
首页 上一页 1 2 3 4 下一页 尾页 1/4/4
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇HTTPResponse object — JSON obj.. 下一篇Python之路:堡垒机实例

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目