python-生成器、迭代器、闭包、装饰器

一、生成器

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

猜你喜欢

转载自blog.csdn.net/poyue8754/article/details/82594236