您的位置:首页 > 编程语言 > Python开发

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

2018-02-01 14:43 501 查看

生成器

  通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: