[python自学笔记]生成器、迭代器、装饰器

生成器

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

通过列表生成式的方式创建生成器

#可以通过列表生成式创建生成器,只需要把[]换成()即可
In [1]: a = [x for x in range(10) ]

In [2]: a
Out[2]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
In [3]: a = (x for x in range(10))

In [4]: a
Out[4]: <generator object <genexpr> at 0x7ffa50d98e08>

#生成器可以通过 next() 函数获得生成器的下一个返回值

In [5]: next(a)
Out[5]: 0

In [6]: next(a)
Out[6]: 1

In [7]: next(a)
Out[7]: 2

In [8]: next(a)
Out[8]: 3

In [9]: next(a)
Out[9]: 4


#此外,生成器可以用for循环遍历
In [12]: a = [x for x in range(10) ]

In [13]: a
Out[13]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

In [14]: for i in a:
   ....:     print(i)
   ....:     
0
1
2
3
4
5
6
7
8
9

通过含yield函数的方式创建生成器

In [30]: def fib(times):
   ....:     n = 0
   ....:     a,b = 0,1
   ....:     while n<times:
   ....:         yield b
   ....:         a,b = b,a+b
   ....:         n+=1
   ....:     return 'done'
   ....: 

In [31]: F = fib(5)

In [32]: next(F)
Out[32]: 1

In [33]: next(F)
Out[33]: 1

In [34]: next(F)
Out[34]: 2

In [35]: next(F)
Out[35]: 3

In [36]: next(F)
Out[36]: 5

In [37]: next(F)
---------------------------------------------------------------------------
StopIteration                             Traceback (most recent call last)
<ipython-input-37-8c2b02b4361a> in <module>()
----> 1 next(F)

StopIteration: done

In [38]: for n in fib(5):
   ....:     print(n)
   ....:     
1
1
2
3
5

In [39]:

迭代器

1. 可迭代对象
  以直接作用于 for 循环的数据类型有以下几种:

  • 一类是集合数据类型,如 list 、 tuple 、 dict 、 set 、 str 等;
  • 一类是 generator ,包括生成器和带 yield 的generator function。

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

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

In [50]: from collections import Iterable

In [51]: isinstance([], Iterable)
Out[51]: True

In [52]: isinstance({}, Iterable)
Out[52]: True

In [53]: isinstance('abc', Iterable)
Out[53]: True

In [54]: isinstance((x for x in range(10)), Iterable)
Out[54]: True

In [55]: isinstance(100, Iterable)
Out[55]: False

而生成器不但可以作用于 for 循环,还可以被 next() 函数不断调用并返回下一个值,直到最后抛出 StopIteration 错误表示无法继续返回下一个值了。
3.迭代器
  可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator。可以使用 isinstance() 判断一个对象是否是 Iterator 对象:
  

In [56]: from collections import Iterator

In [57]: isinstance((x for x in range(10)), Iterator)
Out[57]: True

In [58]: isinstance([], Iterator)
Out[58]: False

In [59]: isinstance({}, Iterator)
Out[59]: False

In [60]: isinstance('abc', Iterator)
Out[60]: False

In [61]: isinstance(100, Iterator)
Out[61]: False

4.iter()函数
  生成器都是 Iterator 对象,但 list 、 dict 、 str 虽然是 Iterable ,却不是 Iterator 。把 list 、 dict 、 str 等 Iterable 变成 Iterator 可以使用 iter() 函数:
  

In [62]: isinstance(iter([]), Iterator)
Out[62]: True

In [63]: isinstance(iter('abc'), Iterator)
Out[63]: True
  • 凡是可作用于 for 循环的对象都是 Iterable 类型;
  • 凡是可作用于 next() 函数的对象都是 Iterator 类型
  • 集合数据类型如 list 、 dict 、 str 等是 Iterable 但不是 Iterator ,不过可以通过 iter()函数获得一个 Iterator 对象。

装饰器

1.闭包
  就是函数里面定义一个函数,并返回,返回值是一个函数,类似于C++里面的函数指针的意思。

#定义一个函数
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))

运行结果:

in test_in 函数, number_in is 100
120

in test_in 函数, number_in is 200
220

2. 函数
  函数名也是个对象,是指向函数体的一个指针,当然也可以指向别的地方

In [1]: def foo():
   ...:     print("foo")
   ...:     

In [2]: foo
Out[2]: <function __main__.foo>

In [3]: foo()
foo
# 让foo指向别的函数
In [4]: foo = lambda x:x+1

In [5]: foo(5)
Out[5]: 6

3. 装饰器
  一个函数功能不够强大,在不修改原来函数的基础上增加新的功能,同装饰模式。
  

def w1(func):
    print("this is w1")
    def inner():
        print("this is an added function")
        func()
    return inner

@w1
def f1():
    print('this is original function')

f1()

执行结果:

this is w1
this is an added function
this is original function

执行过程

@w1的过程就是 f1 = w1(f1)的过程,所以会执行w1函数,但w1内部是定义inner函数,并没有执行,等到执行f1函数的时候,f1指向了inner函数,而func指向了原来的f1函数,因此得到了上面的结果

在比如说:

#定义函数:完成包裹数据
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()))

执行结果:

<b>hello world-1</b>
<i>hello world-2</i>
<b><i>hello world-3</i></b>

执行过程:

仅说明test3,test3函数先被makeItalic函数装饰,再被makeBold装饰,首先第一步,test3被makeItalic函数装饰后,test3指向了makeItalic里面的wrapped函数,也就是返回值为hello world-3,makeItalic的fn指向了原来的test3函数,也就是return “hello world-3”那个,随后再被makeBold函数装饰,那么test3指向了makeBold里面的wrapped函数,makeBold里面的fn指向了上一步test3指向的那个函数。所以执行test3便是执行makeBold函数里面的wrapped函数,只不过是makeBold里面的fn指向了已经被makeItalic装饰过的test

装饰器例子:

from time import ctime, sleep

def timefun(func):
    def wrappedfunc(a, b):
        print("%s called at %s"%(func.__name__, ctime()))
        print(a, b)
        func(a, b)
    return wrappedfunc

@timefun
def foo(a, b):
    print(a+b)

foo(3,5)
sleep(2)
foo(2,4)
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)
from time import ctime, sleep

def timefun(func):
    def wrappedfunc():
        print("%s called at %s"%(func.__name__, ctime()))
        func()
    return wrappedfunc

@timefun
def foo():
    print("I am foo")

@timefun
def getInfo():
    return '----hahah---'

foo()
sleep(2)
foo()


print(getInfo())

执行结果:

foo called at Fri Nov  4 21:55:35 2016
I am foo
foo called at Fri Nov  4 21:55:37 2016
I am foo
getInfo called at Fri Nov  4 21:55:37 2016
None

猜你喜欢

转载自blog.csdn.net/tsfx051435adsl/article/details/79227337