一、生成器
1、什么是生成器
在Python中,这种一边循环一边计算的机制,称为生成器(generator)
2、创建生成器方法
方法1:只要把一个列表生成式的[ ]改为()
In [1]: L = [ x*2 for x in range(5)]
In [2]: L
Out[2]: [0, 2, 4, 6, 8]
In [3]: G = ( x*2 for x in range(5))
In [4]: G
Out[4]: <generator object <genexpr> at 0x000001F84309CEB8>
可以通过next()函数获得生成器的下一个返回值
In [5]: next(G)
Out[5]: 0
In [6]: next(G)
Out[6]: 2
In [7]: next(G)
Out[7]: 4
In [8]: next(G)
Out[8]: 6
In [9]: next(G)
Out[9]: 8
In [10]: next(G)
---------------------------------------------------------------------------
StopIteration Traceback (most recent call last)
<ipython-input-10-b4d1fcb0baf1> in <module>()
----> 1 next(G)
StopIteration:
生成器是可迭代的对象,我们可以通过for循环来迭代它
In [11]: G = ( x*2 for x in range(5))
In [12]: for x in G:
...: print(x)
...:
0
2
4
6
8
方法2:使用yield
In [13]: def fib(times):
...: n = 0
...: a, b = 0, 1
...: while n < times:
...: yield b
...: a, b = b, a+b
...: n += 1
...: return 'done'
...:
...:
In [14]: F = fib(5)
In [15]: next(F)
Out[15]: 1
In [16]: next(F)
Out[16]: 1
In [17]: next(F)
Out[17]: 2
In [18]: next(F)
Out[18]: 3
In [19]: next(F)
Out[19]: 5
In [20]: next(F)
---------------------------------------------------------------------------
StopIteration Traceback (most recent call last)
<ipython-input-20-372178f5f53b> in <module>()
----> 1 next(F)
StopIteration: done
In [21]: for n in fib(5):
...: print(n)
...:
1
1
2
3
5
但是用for循环调用generator时,发现拿不到generator的ruturn的返回值。如果想要拿到返回值,必须捕获StopIteration错误,返回值包含在StopIteration的value中。
In [22]: g = fib(5)
In [23]: while True:
...: try:
...: x = next(g)
...: print("value:%d"%x)
...: except StopIteration as e:
...: print("生成器返回值:%s"%e.value)
...: break
...:
value:1
value:1
value:2
value:3
value:5
生成器返回值:done
总结:生成器是这样一个函数,它记住上一次返回时在函数体中的位置。对生成器函数的第二次(或第n次)调用跳转至该函数中间,而上次调用的所有局部变量都白痴不变。
生成器的特点:1、节约内存 2、迭代到下一次的调用时,所使用的参数都是第一次所保留下的,即是说,在整个所有函数调用的参数都是第一次所调用时保留的,而不是新创建的。
二、迭代器
迭代是访问集合元素的一种方式。迭代器是一个可以记住遍历的位置的对象。迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退。
1.可迭代对象
以直接作用于for循环的数据类型有以下几种:
一类是集合数据类型,如list、tuple、dict、set、str等
一类是generator, 包括生成器和带yield的generator function
这些可以直接作用于for循环的对象统称为可迭代对象:Iterable。
2、判断是否可以迭代
可以使用isinstance()判断一个对象是否是Iterable对象:
In [24]: from collections import Iterable
In [25]: isinstance([],Iterable)
Out[25]: True
In [26]: isinstance({},Iterable)
Out[26]: True
In [27]: isinstance('abc',Iterable)
Out[27]: True
In [28]: isinstance(( x for x in range(10)), Iterable)
Out[28]: True
In [29]: isinstance(100, Iterable)
Out[29]: False
3、迭代器
可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator,可以使用isinstance()判断一个对象是否是Iterator对象。
In [30]: from collections import Iterator
In [31]: isinstance(( x for x in range(10)), Iterator)
Out[31]: True
In [32]: isinstance([], Iterator)
Out[32]: False
In [33]: isinstance({}, Iterator)
Out[33]: False
In [34]: isinstance('abc', Iterator)
Out[34]: False
In [35]: isinstance(100, Iterator)
Out[35]: False
In [36]: In [34]: isinstance('abc', Iterator)
...: Out[34]: False
...:
...: In [35]: isinstance(100, Iterator)
...: Out[35]: False
...:
4、iter()函数
生成器都是Iterator对象,但list、dict、str虽然是Iterable,却不是Iterator(迭代器一定可以迭代,可迭代的不一定是迭代器)
如果把list、dict、str等Iterable变成Iterator可以使用iter()函数
In [37]: isinstance(iter([]), Iterator)
Out[37]: True
In [38]: isinstance(iter('abc'), Iterator)
Out[38]: True
总结:
凡是可作用于for循环的对象都是Iterable类型
凡是可以作用于next()函数的对象都是Iterator类型
集合数据类型如list、dict、str等是Iterable但不是Iterator,不过可以通过iter()函数获得一个Iterator对象。
三、闭包
1、什么是闭包
# 定义一个函数
def test(number):
# 在函数内部再定义一个函数,并且这个函数用到了外边函数的变量,
# 那么将这个函数以及用到的一些变量称之为闭包
def test_in(number_in):
print("in test_in 函数,number_in is %d"%number_in)
return number+number_in
# 其实这里返回的就是闭包的结果
return test_in
# 给test函数赋值,这个20就是给参数number
ret = test(20)
# 注意这里的100其实给参数number_in
print(ret(100))
# 注意这里的200其实给参数number_in
print(ret(200))
#result:
# in test_in 函数,number_in is 100
# 120
# in test_in 函数,number_in is 200
# 220
def line_conf(a, b):
def line(x):
return a*x + b
return line
line1 = line_conf(1, 1)
line2 = line_conf(4, 5)
print(line1(5))
print(line2(5))
# result:
# 6
# 25
这样就确定了函数的最终形式(y = x + 1 和 y = 4x + 5),闭包具有提高代码可复用性的作用。
四、装饰器
#定义函数:完成包裹数据
def makeBold(fn):
def wrapped():
return "<b>" + fn() + "</b>"
return wrapped
#定义函数:完成包裹数据
def makeItalic(fn):
def wrapped():
return "<i>" + fn() + "</i>"
return wrapped
@makeBold
def test1():
return "hello world-1"
@makeItalic
def test2():
return "hello world-2"
@makeBold
@makeItalic
def test3():
return "hello world-3"
print(test1())
print(test2())
print(test3())
# result:
# <b>hello world-1</b>
# <i>hello world-2</i>
# <b><i>hello world-3</i></b>
from time import ctime, sleep
def timefun(func):
def wrappedfunc(*args, **kwargs):
print("%s called at %s"%(func.__name__, ctime()))
func(*args, **kwargs)
return wrappedfunc
@timefun
def foo(a, b, c):
print(a+b+c)
foo(3,5,7)
sleep(2)
foo(2,4,9)
#result:
# foo called at Mon Sep 10 21:04:21 2018
# 15
# foo called at Mon Sep 10 21:04:23 2018
# 15