打赏

python学习之路-day4-装饰器&json&pickle

本节内容

  1. 迭代器&生成器
  2. 装饰器
  3. Json & pickle 数据序列化

一、生成器

1、列表生成式

>>> L = [x * x for x in range(10)]

>>> L

[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

2、生成器

只有在调用时才会生成相应的数据,只有一个方法:__next__()方法。next(),也就是又next方法的

生成器

通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。

所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器:generator。

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

 1 >>> L = [x * x for x in range(10)]
 2 
 3 >>> L
 4 
 5 [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
 6 
 7 >>> g = (x * x for x in range(10))
 8 
 9 >>> g
10 
11 <generator object <genexpr> at 0x1022ef630> 

创建Lg的区别仅在于最外层的[]()L是一个list,而g是一个generator。

我们可以直接打印出list的每一个元素,但我们怎么打印出generator的每一个元素呢?

如果要一个一个打印出来,可以通过next()函数获得generator的下一个返回值:

 1 >>> next(g)
 2 
 3 >>> next(g)
 4 
 5 >>> next(g)
 6 
 7 >>> next(g)
 8 
 9 >>> next(g)
10 
11 >>> next(g)
12 
13 >>> next(g)
14 
15 >>> next(g)
16 
17 >>> next(g)
18 
19 >>> next(g)
20 
21 >>> next(g)
22 
23 Traceback (most recent call last):
24 
25   File "<stdin>", line 1, in <module>
26 
27 StopIteration

 如果一个函数定义中包含yield关键字,那么这个函数就不再是一个普通函数,而是一个generator:

普通函数:

 1  1 def fib(max):
 2  2     n,a,b = 0,0,1
 3  3     while  n<max:
 4  4         print(b)
 5  5         #yield b
 6  6         a,b=b,a+b
 7  7         n = n+1
 8  8     return 'done'
 9  9 t = fib(11)
10 10 print(t)
11 11 输出结果:
12 12 1
13 13 1
14 14 2
15 15 3
16 16 5
17 17 8
18 18 13
19 19 21
20 20 34
21 21 55
22 22 89
23 23 done
24 
25 上面函数变成生成器,只需要把print(b)改为yield b就可以了:
26 
27 
28 def fib(max):
29 
30     n,a,b = 0,0,1
31 
32     while  n<max:
33 
34         #print(b)
35 
36         yield b
37 
38         a,b=b,a+b
39 
40         n = n+1
41 
42     return 'done'
43 
44 t = fib(11)
45 
46 print(t)
47 
48  
49 
50 输出结果:
51 
52 <generator object fib at 0x00000000010F59E8>

注:赋值语句:
a, b = b, a + b

相当于:

1 t = (b, a + b) # t是一个tuple
2 a = t[0]
3 b = t[1]

这里,最难理解的就是generator和函数的执行流程不一样。函数是顺序执行,遇到return语句或者最后一行函数语句就返回。而变成generator的函数,在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行。

变成生成器之后并没有运行,而是在要输出的时候才运行:(每次next,输出一次)

def fib(max):
    n,a,b = 0,0,1
    while  n<max:
        #print(b)
        yield b                #碰到yield,程序中断, 出到函数外面在遇到next的时候在回来接着往下走

        a,b=b,a+b
        n = n+1
    return 'done'
t = fib(11)
print(t)
print(t.__next__())
print(t.__next__())
print(t.__next__())
print("---------")
print(t.__next__())
输出结果:
1
1
2
---------
3
View Code


再来一例:

 1 def consumer(name):
 2     print("%s 准备吃包子啦!" %name)
 3     while True:
 4         baozi =  yield       #碰到yield退出程序,遇到c.__next__()时在进来继续往下走
 5         print("包子[%s]来了,被【%s】吃了!" %(baozi,name))
 6 c = consumer("lsp")
 7 c.__next__()
 8 c.__next__()
 9 c.__next__()
10 c.__next__()
11 
12 输出结果:
13 lsp 准备吃包子啦!
14 包子[None]来了,被【lsp】吃了!   
15 #yield是none值,可以通过send给yield传值,见下例
16 包子[None]来了,被【lsp】吃了!
17 包子[None]来了,被【lsp】吃了!
View Code

**最后一例**

import time
def consumer(name):
    print("%s 准备吃包子啦!" %name)
    while True:
        baozi =  yield      #碰到yield退出程序,遇到c.__next__()或者(send)时在进来继续往下走(只要有yield就是生成器)
        print("包子[%s]来了,被【%s】吃了!" %(baozi,name))
def producer(name):
    c=consumer('lw')       #因为是生成器,所以不会输出任何东西
    c2 = consumer('lsp')
    c.__next__()           #输出lw准备吃包子了
    c2.__next__()           #输出lsp准备吃包子了
    print("我开始准备做包子了!")   #输出我开始做包子了
    for i in range(3):              #循环
        time.sleep(1)               #sleep  1秒
        print("做了1个包子")        #做了一个包子
        c.send(i)          #将i的值传给yield
        c2.send(i)          #将i的值传给yield
producer("alex")            #调用函数
输出结果:
lw 准备吃包子啦!
lsp 准备吃包子啦!
我开始准备做包子了!
做了1个包子
包子[0]来了,被【lw】吃了!
包子[0]来了,被【lsp】吃了!
做了1个包子
包子[1]来了,被【lw】吃了!
包子[1]来了,被【lsp】吃了!
做了1个包子
包子[2]来了,被【lw】吃了!
包子[2]来了,被【lsp】吃了!
View Code


二、迭代器

 

可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator。

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

只要有next的方法,就一定是一个迭代器

for line in f:   #就是一个迭代器

接上面生成器的例子:

 1 def fib(max):
 2     n,a,b = 0,0,1
 3     while  n<max:
 4         #print(b)
 5         yield b
 6         a,b=b,a+b
 7         n = n+1
 8     return 'done'
 9 t = fib(11)
10 for i in t:
11     print(i)
12 输出结果:
13 1
14 1
15 2
16 3
17 5
18 8
19 13
20 21
21 34
22 55
23 89
View Code

三、装饰器

装饰器:本质是函数(装饰其他函数),就是为其他函数添加附加功能

原则:

  1. 不能修改被修饰的函数的源代码
  2. 不能修改被装饰的函数的调用方式

原函数代码和调用方式 不变,不知道有装饰器在装饰他(一句话,源函数代码和调用方式一点都不变,实现改变功能的函数,即是装饰器)

例一:

import time
def bar():              #原函数
    time.sleep(3)
    print('in the bar')
def test1(func):
    start_time=time.time()
    func()                 #调用函数bar,因为func= bar,所以这里func()== bar(),即调用上面的函数
    stop_time=time.time()
    print("the func time is %s" %(stop_time-start_time))

#bar()  #原函数调用方式
test1(bar)      #调用函数test1,func = bar ,这样虽然实现了修改原函数功能,但是调用方式改变了
View Code


例二:

 1     原函数:
 2 import time
 3 def test1():         # 原函数1
 4     print("this is test1")  
 5 def test2():        #原函数2       
 6     print("this is test2")
 7 test1()            #原函数调用方式
 8 test2()              #原函数调用方式
 9 -----------------------------
10 加装饰器(加功能:程序运行时间)
11    
12 import time
13 def timer(func):
14     def deco():
15         start_time = time.time()
16         func()    #test1 = func()--->test1() //#test2 = func()--->test2()
17         stop_time = time.time()
18         print("the func run time is %s" %(stop_time-start_time))
19     return deco    #将deco的函数的内存地址返回,就是test1 == deco函数的内存地址!
20 @timer   #test1=timer(test1)    test1 == deco函数的内存地址!
21 def test1():   #test1 == deco函数的内存地址!test1()即执行deco函数,真正的test1()到deco函数里面遇到func()才会执行
22     time.sleep(1)
23     print("this is test1")
24 @timer  #test2=timer(test1)
25 def test2():
26     time.sleep(1)
27     print("this is test2")
28 test1()
29 test2()
View Code

 终极装饰器:

 1 # __author__ = 'lw'
 2 import time
 3 user,passwd = 'lw','lw123'
 4 def auth(auth_type):
 5     print('auth_func:',auth_type)
 6     def outer_wrapper(func):
 7         def wrapper(*args,**kwargs):
 8             print("wrapper func args:",*args,**kwargs)
 9             if auth_type == "local":
10                 username = input("Username:").strip()
11                 password = input("password:").strip()
12                 if username == user and passwd == password:
13                     print("\033[32;1mUser has passwd authentication\033[0m")
14                     res = func(*args,**kwargs)      #from home
15                     print("---after authentication")
16                     return res
17                 else:
18                     exit("\033[31;1mInvalid username or password\033[0m")
19             elif auth_type == "ldap":
20                 print("welcome to ldap")
21         return wrapper
22     return outer_wrapper
23 def index():
24     print("welcome to index page")
25 @auth(auth_type="local")   #home = wrapper()
26 def home():
27     print("welcome to home page")
28     return  "from home"
29 def bbs():
30     print("welcome to bbs page")
31 index()
32 print(home())  #wrapper()
33 bbs()
View Code

四、 json&&pickle

JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式。它基于JavaScript(Standard ECMA-262 3rd Edition - December 1999)的一个子集。 JSON采用完全独立于语言的文本格式,但是也使用了类似于C语言家族的习惯(包括C, C++, C#, Java, JavaScript, Perl, Python等)。这些特性使JSON成为理想的数据交换语言。易于人阅读和编写,同时也易于机器解析和生成。

 json在所以语言中通用

引用模块

 

import json

重要函数

  • 编码:把一个Python对象编码转换成Json字符串   json.dumps()
  • 解码:把Json格式字符串解码转换成Python对象   json.loads()

例子

序列化

将内存中的信息写入到文件

#!/usr/bin/python

import json
info = {

        'name':'alex',
        'age':'22'
}
f = open("test.txt","w")

f.write(json.dumps(info))

f.close()
[root@test1 python]# 

 反序列化

将文件中的信息读取出来

[root@test1 python]# cat fanxuliehua.py 
#!/usr/bin/python

import json
f = open("test.txt","r")

data = json.loads(f.read())

print(data)
print(data["name"])

[root@test1 python]# python fanxuliehua.py       
{u'age': u'22', u'name': u'alex'}
alex
[root@test1 python]#

 json只能序列化简单的数据类型,不能反序列化函数等复杂的数据类型,想要序列化复杂的数据,需要使用pickle,用法和json完全一样,只是序列化的时候变成二进制类型,即在打开文件的时候要用wb和rb

 pickle.dump(info,f) ==f.write(pickle.dumps(info))

posted @ 2016-08-19 09:51  隔壁老梁  阅读(277)  评论(0编辑  收藏  举报