Python自学,Day4-Python基础

本节内容

  1、迭代器&生成器

  2、装饰器

  3、Json & pickle 数据序列化

  4、软件目录结构规范

  5、作业:ATM项目开发

1、装饰器 decorator                              

定义:本质是函数,功能是用来装饰其他函数,就是为其他函数添加附加功能

原则:

1、不能修改被修饰函数的源代码

2、不能修改被装饰函数的调用方式

实现装饰器的知识储备:

1、函数即“变量”

2、高阶函数

  满足以下一个条件即可

  a、把一个函数名当实参传给另一个函数

  b、返回值中包含函数名

3、嵌套函数

 高阶函数+嵌套函数->装饰器

 

函数即“变量”:函数可以理解为和变量一样的概念,在内存中均是通过定义内存及对应的内存地址来存储和调用

高阶函数(条件a)

 1 def test(func):
 2     print(func)
 3     func()
 4 
 5 def bar():
 6     print('in the bar')
 7 
 8 test(bar)
 9 
10 #执行结果
11 <function bar at 0x10e042158> #代表bar()的内存地址
12 in the bar

改动该高阶函数

 1 import time
 2 
 3 def test(func):
 4     staart_time=time.time()#获取当前时间
 5     func()
 6     stop_time=time.time()
 7     print('the running time of bar is %s' %(stop_time-staart_time))
 8 
 9 def bar():
10     time.sleep(3) #睡眠3秒
11     print('in the bar')
12 
13 test(bar)
14 
15 #result
16 in the bar
17 the running time of bar is 3.000331163406372

其中bar()为源函数,test()为装饰函数,但是存在方法改变了bar()函数的调用方式,原本的调用方式是:bar(),现在需要运行装饰函数,则需将调用函数变更为:test(bar)

高阶函数(条件b)

 1 import time
 2 
 3 def test2(func): #装饰函数
 4     print('in the test2')
 5     return func
 6 
 7 def orl(): #源函数
 8     time.sleep(3)
 9     print('in the orl')
10 
11 orl=test2(orl) #将返回函数的内存地址重新赋值给orl
12 orl() #不改变源函数的调用方式
13 
14 #result
15 in the test2
16 in the orl

  嵌套函数

 1 def foo():
 2     print('in the foo')
 3     def bar(): #嵌套函数
 4         print('in the bar')
 5     bar()
 6 
 7 foo()
 8 
 9 
10 #result
11 in the foo
12 in the bar

  嵌套函数作用域

 1 x=0
 2 def grandpa():
 3     x=1
 4     def dad():
 5         x=2
 6         def son():
 7             x=3
 8             print('son',x)
 9         son()
10         print('dad',x)
11     dad()
12     print('grandpa',x)
13 
14 grandpa()
15 
16 #result
17 son 3
18 dad 2
19 grandpa 1

  装饰器初现端倪

 1 '''
 2 需求:
 3 1、新增个装饰器,统计已存在的两个函数的运行时间
 4 2、不能改变原有函数和原有调用方式
 5 '''
 6 
 7 import time
 8 
 9 def timer(func): #装饰器
10     def run_time():
11         start_time=time.time()
12         func() #运行父级函数中获取的行参函数(嵌套函数)
13         stop_time=time.time()
14         print('the running time of func is %s' %(stop_time-start_time))
15     return run_time #返回函数
16 
17 def test1():
18     time.sleep(2)
19     print('in the test1')
20 
21 def test2():
22     time.sleep(4)
23     print('in the test2')
24 
25 test1=timer(test1) #将函数的内存地址获取,此时test1获取的时run_time的内存地址
26 test1()
27 
28 test2=timer(test2)
29 test2()
30 
31 #result
32 in the test1
33 the running time of func is 2.0049290657043457
34 in the test2
35 the running time of func is 4.002476930618286

  伤痛:每次都需要将test1=timer(test1)函数再重新写一下,是否可以简化操作???这个必须有...

  改良版的装饰器

 1 '''
 2 需求:
 3 1、新增个装饰器,统计已存在的两个函数的运行时间
 4 2、不能改变原有函数和原有调用方式
 5 '''
 6 
 7 import time
 8 
 9 def timer(func): #装饰器
10     def run_time():
11         start_time=time.time()
12         func() #运行父级函数中获取的行参函数(嵌套函数)
13         stop_time=time.time()
14         print('the running time of func is %s' %(stop_time-start_time))
15     return run_time #返回函数
16 
17 @timer  #相当于test1=timer(test1)
18 def test1():
19     time.sleep(2)
20     print('in the test1')
21 
22 @timer #相当于test2=timer(test2)
23 def test2():
24     time.sleep(4)
25     print('in the test2')
26 
27 #test1=timer(test1) #将函数的内存地址获取,此时test1获取的时run_time的内存地址
28 test1()
29 
30 #test2=timer(test2)
31 test2()
32 
33 
34 #result
35 in the test1
36 the running time of func is 2.0053460597991943
37 in the test2
38 the running time of func is 4.003633260726929  

  在原函数头部添加 @装饰器函数名称 来调用装饰器函数

  那,如果有100个需要装饰的原函数,是否就需要写100次 @XXX??? 答:是的...吐一口老血

  那,你的test1和test2都是没有参数的函数,实际中很多都是存在参数的函数,存在参数的函数,这个装饰器可以用吗?答:貌似会报错耶...再吐一口老血

  有招治参数这个问题没?答:这个必须有

  且看,通用装饰器

 1 def timer(func): #装饰器
 2     def run_time(*args,**kwargs): #使用不确定参数
 3         start_time=time.time()
 4         func(*args,**kwargs) #运行父级函数中获取的行参函数(嵌套函数)
 5         stop_time=time.time()
 6         print('the running time of func is %s' %(stop_time-start_time))
 7     return run_time #返回函数
 8 
 9 @timer  #相当于test1=timer(test1)
10 def test1():
11     time.sleep(2)
12     print('in the test1')
13 
14 @timer #相当于test2=timer(test2)
15 def test2(name1,name2):
16     time.sleep(4)
17     print('in the test2,name:',name1,name2)
18 
19 test1()
20 test2('shang','ace')
21 
22 
23 #result
24 in the test1
25 the running time of func is 2.0028507709503174
26 in the test2,name: shang ace
27 the running time of func is 4.004335165023804

  ps:在没听课件老师的讲解之前,我自己写出来的,大写的流弊啊,机智一匹....

  少侠,要不要搞一场景展示下修炼成果?答:必须的嘛,对于我这么低调的人!

  装饰器小试牛刀

  需求如下:

需求:
1、模拟网页浏览
2、假设目前网站上有三个页面均不需要验证登录态
现在调整为
1、首页index不需要校验登录
2、home和trade页面需要校验登录
3、登录用户的用户名和密码数据从字典UserTable中获取
4、不改变原函数、调用方式、返回结果等信息
5、home和trade页面,一旦用户登录成功,则无需再登录

  ps:话说老师给的需求太低,自己给自己加量,要不怎么能显示自己机智一匹呢~

  话说,自己又写出来了,今天是怎么了,我竟如此机智!!!

 1 UserTable={
 2     'bilian':'111',
 3     'shang':'123',
 4     'ace':'456',
 5 }
 6 
 7 status={
 8     'cookie':0  #记录登录态 0代表未登录 1代表登录
 9 }
10 
11 def logger(msg):
12     print('logger:',msg)
13 
14 
15 #添加装饰器
16 def decorator(func):
17     def login(*args,**kwargs):
18         if status['cookie']==0:
19             username=input('Username:')
20             password=input('Password:')
21             if username in UserTable:
22                 if password==UserTable[username]:
23                     status['cookie']=1
24                     logger('welcome back')
25                     func(*args,**kwargs)
26                 else:
27                     logger('wrong password')
28                     exit()
29             else:
30                 logger('invalid username')
31                 exit()
32         else:
33             logger('you have landed')
34             func(*args,**kwargs)
35     return login
36 
37 
38 #使用每一个函数代表调用每一个页面
39 def index():
40     print('welcome to index page')
41 
42 @decorator
43 def home():
44     print('welcome to home page')
45 
46 @decorator
47 def trade():
48     print('welcome to trade page')
49 
50 index()
51 home()
52 trade()
View Code

  咦,老师让在原函数中添加返回值,这个我搞一搞试一试撒。

  home原函数中改动:return '宝儿姐语录:我是台湾来的交换生'--脑补这个场景,宝儿姐老牛逼了

  result:卧擦,加完装饰器之后,打印home()竟然直接返回None,这个是什么鬼~~~

  老师支招,添加接收项,然后return即可。

 1 '''
 2 需求:
 3 1、模拟网页浏览
 4 2、假设目前网站上有三个页面均不需要验证登录态
 5 现在调整为
 6 1、首页index不需要校验登录
 7 2、home和trade页面需要校验登录
 8 3、登录用户的用户名和密码数据从字典UserTable中获取
 9 4、不改变原函数、调用方式、返回结果等信息
10 5、home和trade页面,一旦用户登录成功,则无需再登录
11 '''
12 
13 UserTable={
14     'bilian':'111',
15     'shang':'123',
16     'ace':'456',
17 }
18 
19 status={
20     'cookie':0  #记录登录态 0代表未登录 1代表登录
21 }
22 
23 def logger(msg):
24     print('logger:',msg)
25 
26 
27 #添加装饰器
28 def decorator(func):
29     def login(*args,**kwargs):
30         if status['cookie']==0:
31             username=input('Username:')
32             password=input('Password:')
33             if username in UserTable:
34                 if password==UserTable[username]:
35                     status['cookie']=1
36                     logger('welcome back')
37                     result=func(*args,**kwargs) #用res来接收执行结果
38                     return result #返回认证结果
39                 else:
40                     logger('wrong password')
41                     exit()
42             else:
43                 logger('invalid username')
44                 exit()
45         else:
46             logger('you have landed')
47             func(*args,**kwargs)
48     return login
49 
50 
51 #使用每一个函数代表调用每一个页面
52 def index():
53     print('welcome to index page')
54 
55 @decorator
56 def home():
57     print('welcome to home page')
58     return '宝儿姐语录:我是台湾来的交换生!'
59 
60 @decorator
61 def trade():
62     print('welcome to trade page')
63 
64 index()
65 print(home())
66 trade()
View Code

  如果不同场景,需要装饰根据传递的参数确定执行的不同逻辑,此处应该如何处理?

'''
需求:
1、模拟网页浏览
2、假设目前网站上有三个页面均不需要验证登录态
现在调整为
1、首页index不需要校验登录
2、home和trade页面需要校验登录
3、登录用户的用户名和密码数据从字典UserTable中获取
4、不改变原函数、调用方式、返回结果等信息
5、home和trade页面,一旦用户登录成功,则无需再登录
'''

UserTable={
    'bilian':'111',
    'shang':'123',
    'ace':'456',
}

status={
    'cookie':0  #记录登录态 0代表未登录 1代表登录
}

def logger(msg):
    print('logger:',msg)


#添加装饰器
def decorator(login_type):
    print('deco login_type:',login_type)
    def LoginType(func):
        def login(*args,**kwargs):
            if status['cookie']==0:
                username = input('Username:')
                password = input('Password:')
                if login_type=='local':
                    if username in UserTable:
                        if password==UserTable[username]:
                            #status['cookie']=1 执行trade()函数时,需要重新进行下用户名和密码的输入,已确定可以执行WeChat的逻辑
                            logger('welcome back')
                            result=func(*args,**kwargs) #用res来接收执行结果
                            return result #返回认证结果
                        else:
                            logger('wrong password')
                            exit()
                    else:
                        logger('invalid username')
                        exit()
                elif login_type=='WeChat':
                    print('WeChat API Login')
                    exit()
            else:
                logger('you have landed')
                func(*args,**kwargs)
        return login
    return LoginType

#使用每一个函数代表调用每一个页面
def index():
    print('welcome to index page')

#home使用本地用户数据进行校验
@decorator(login_type='local')
def home():
    print('welcome to home page')
    return '宝儿姐语录:我是台湾来的交换生!'


#trade使用第三方微信的账户信息进行校验
@decorator(login_type='WeChat')
def trade():
    print('welcome to trade page')


index()
print(home())
trade()
View Code

  备注:

  1、在装饰器调用函数上增加参数,用于区分不同的场景,@decorator(login_type='local')

  2、在装饰器调用时,先透传login_type参数,所以在最外层的decorator()需要添加参数,用以接收设置的参数,def decorator(login_type)

  3、需要再新建一层嵌套函数,用以接受原来的func函数的高阶函数,LoginType(func),并且需要新增该函数的返回return LoginType

  4、在程序里面校验login_type的类型,在执行trade函数时,需要重新在设置下用户名和密码,以便可以执行login_type的判断

  ps:老师讲的已经完全高潮了,但是宝宝内心只是大概知道其中的逻辑,具体函数执行的顺序,已经夜深头昏脑胀的搞不明白,以后再慢慢梳理吧...

 2、迭代器                          

  列表生成式

1 # 列表生成式
2 a=[ i*2 for i in range(10) ]
3 print(a)
4 
5 
6 #result
7 [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]

 

  其中a=[ i*2 for i in range(10) ]就是列表生成器

列表生成器相当于如下代码:

1 a=[]  #声明一个空的列表
2 for i in range(10):
3     a.append(i*2) #给列表添加值
4 print(a)

  当然,也有高bigger的操作~

1 # 高级操作
2 def func(i):
3     data=i*i
4     return data
5 arr=[ func(i) for i in range(10) ]
6 print(arr)
7 
8 #result
9 [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

  其中,将i替换成func函数的形式,666...

  • 生成器

  摘录金角大王:

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

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

  ps:嗯嗯,好有道理的样子...不过,如果这样的话,那为什么还要用列表呢?是否可以def一个函数来代表该算法,每次调用的时候,直接计算出来即可,这个不就解决这个困境了吗???

  创建生成器:

(i*2 for i in range(10))

  定义该生成器,在内存中只是对一个内存地址,其实并没有生成相应的各个元素

打印该生成器,如下:

1 c=(i*2 for i in range(10))
2 print(c)
3 
4 #result
5 <generator object <genexpr> at 0x1007f59a8>    #生成器对应的内存地址

  没办法直接查询生成器指定角标对应的参数,必须一个一个参数的依次生成,然后读取

 1 c=(i*2 for i in range(10))
 2 print(c)
 3 print(c.__next__())
 4 for i in range(8):
 5     print(c.__next__())
 6 
 7 #result
 8 <generator object <genexpr> at 0x10de289a8>
 9 0  #第一次读取的c中的参数
10 2  #循环获取的第一个参数  
11 4
12 6
13 8
14 10
15 12
16 14
17 16

  备注:生成器采用c.__next__()的方式生成并获取相应的参数

  斐波那契数列:1、1、2、3、5、8、13、21、34、……F(1)=1,F(2)=1, F(n)=F(n-1)+F(n-2)(n>=3,n∈N*)

  老师给的代码:

 1 def fib(num):
 2     n,a,b=0,0,1
 3     while n<num:
 4         print(b)
 5         a,b=b,a+b
 6         n=n+1
 7 
 8 fib(10) #打印斐波那契数列的前10个参数
 9 
10 #result
11 1
12 1
13 2
14 3
15 5
16 8
17 13
18 21
19 34
20 55

  原本以为n,a,b=0,0,1是n=0,a=0,b=1,以及a,b=b,a+b是a=b,b=a+b的含义,可是,调整代码后执行结果,很是让宝宝吃惊....

def fib(num):
    #n,a,b=0,0,1
    n=0
    a=0
    b=1
    while n<num:
        print(b)
        #a,b=b,a+b
        a=b
        b=a+b
        n=n+1

fib(10) 

#result
1
2
4
8
16
32
64
128
256
512

  这是在做一个累加的数列,完全不是斐波那契数列,且听老师讲解。

  老师讲解a,b=b,a+b不是a=b,b=a+b的含义,是元组的概念,代码如下:

 1 def fib(num):
 2     #n,a,b=0,0,1
 3     t1 = (0, 0, 1)
 4     n = t1[0]
 5     a = t1[1]
 6     b = t1[2]
 7     while n<num:
 8         print(b)
 9         #a,b=b,a+b
10         t2 = (b, a + b)
11         a = t2[0]
12         b = t2[1]
13         n=n+1
14 
15 fib(10) #打印斐波那契数列的前10个参数
16 
17 #result
18 1
19 1
20 2
21 3
22 5
23 8
24 13
25 21
26 34
27 55
View Code

  备注:其中t2是一个动态元组,每次循环,对应的t2中元素均一直在变化;

  ps:看着很有道理的样子,但是感觉这种完全可以有其他替代方式,我自己搞一发试一下->_->

 1 '''
 2 斐波那契函数的数学运算符
 3 F(1)=1,F(2)=1, F(n)=F(n-1)+F(n-2)(n>=3,n∈N*)
 4 '''
 5 
 6 #哥就是不服
 7 def fib(num):
 8     a=[]
 9     for i in range(num):
10         if i==0:
11             a.append(1)
12         elif i==1:
13             a.append(1)
14         else:
15             a.append(a[i-1]+a[i-2])
16     return a
17 
18 print(fib(10))
19 
20 #result
21 [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
View Code

  我去,叼叼叼,自己搞出来的感觉就是爽....

  老师给的斐波那契代码,稍微调整一下即可生成相应的generator,要把fib函数变成generator,只需要把print(b)改为yield b就可以了

 1 def fib(num):
 2     n,a,b=0,0,1
 3     while n<num:
 4         #print(b)
 5         yield b #将函数改成生成器
 6         a,b=b,a+b
 7         n=n+1
 8 
 9 f=fib(10) #打印斐波那契数列的前10个参数
10 print(f.__next__())
11 print('-----我是分隔符-----')
12 print(f.__next__())
13 print(f.__next__())
14 print('调用另一个程序执行相应逻辑')
15 print(f.__next__())
16 print(f.__next__())
17 
18 #result
19 1
20 -----我是分隔符-----
21 1
22 2
23 调用另一个程序执行相应逻辑
24 3
25 5

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

 1 def fib(num):
 2     n,a,b=0,0,1
 3     while n<num:
 4         #print(b)
 5         yield b #将函数改成生成器
 6         a,b=b,a+b
 7         n=n+1
 8 
 9 f=fib(10) #打印斐波那契数列的前10个参数
10 print(f)
11 
12 #result
13 <generator object fib at 0x105a759a8>

这里,最难理解的就是generator和函数的执行流程不一样

函数是顺序执行,遇到return语句或者最后一行函数语句就返回。而变成generator的函数,在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行。在上面fib的例子,我们在循环过程中不断调用yield,就会不断中断。

通常,把函数改成generator后,我们基本上从来不会用next()来获取下一个返回值,而是直接使用for循环来迭代:

 1 def fib(num):
 2     n,a,b=0,0,1
 3     while n<num:
 4         #print(b)
 5         yield b #将函数改成生成器
 6         a,b=b,a+b
 7         n=n+1
 8 
 9 f=fib(10) #打印斐波那契数列的前10个参数
10 print(f)
11 
12 for i in range(10):
13     print(f.__next__())
14 
15 #result
16 <generator object fib at 0x101ac59a8>  
17 1
18 1
19 2
20 3
21 5
22 8
23 13
24 21
25 34
26 55

但是用for循环调用generator时,发现拿不到generator的return语句的返回值,如果想要拿到返回值,必须捕获StopIteration错误,返回值包含在StopIterationvalue中:

 1 def fib(num):
 2     n,a,b=0,0,1
 3     while n<num:
 4         #print(b)
 5         yield b #将函数改成生成器
 6         a,b=b,a+b
 7         n=n+1
 8     return '已撸完'
 9 
10 f=fib(10) #打印斐波那契数列的前10个参数
11 
12 #采用异常处理,用于抓取return结果
13 while True:
14      try:
15          x = next(f)
16          print('f:', x)
17      except StopIteration as e:
18          print('Generator return value:', e.value)
19          break
20 
21 #result
22 f: 1
23 f: 1
24 f: 2
25 f: 3
26 f: 5
27 f: 8
28 f: 13
29 f: 21
30 f: 34
31 f: 55
32 Generator return value: 已撸完
View Code 

  备注:其中循环执行完成之后,通过抓取报错信息的机制,获取到return的内容

  • 生成器的运用

  可通过yield实现在单线程的情况下实现并发运算的效果

#生成器并行

import time
def consumer(name):
    print("%s 准备吃包子啦!" %name)
    while True:
       baozi = yield #在consumer中只是中断标示

       print("包子[%s]来了,被[%s]吃了!" %(baozi,name))

def producer(name):
    c = consumer('A')
    c2 = consumer('B')
    c.__next__()    #consumer运行到yield处返回
    c2.__next__()
    print("老子开始准备做包子啦!")
    for i in range(10):
        time.sleep(1)
        print("做了2个包子!")
        c.send(i) #将i的value透传至yield赋值参数
        c2.send(i)

producer("alex")

  备注:c = consumer('A'),只是生成该迭代器,需要用c.__next__()开始执行生成器

3、迭代器                                                   

可以直接作用于for循环的数据类型有以下几种:

一类是集合数据类型,如listtupledictsetstr等;

一类是generator,包括生成器和带yield的generator function。

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

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

 1 from collections.abc import Iterable
 2 
 3 #列表是可以迭代的
 4 print(isinstance([],Iterable))
 5 
 6 #字典是可以迭代的
 7 print(isinstance({}, Iterable))
 8 
 9 #字符串是可以迭代的
10 print(isinstance('abc', Iterable))
11 
12 #for循环可以迭代的
13 print(isinstance((x for x in range(10)), Iterable))
14 
15 #数字不可以迭代的
16 print(isinstance(100, Iterable))
17 
18 #result
19 True
20 True
21 True
22 True
23 False

而生成器不但可以作用于for循环,还可以被next()函数不断调用并返回下一个值,直到最后抛出StopIteration错误表示无法继续返回下一个值了。

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

生成器都是Iterator对象,但listdictstr虽然是Iterable,却不是Iterator

可以使用isinstance()判断一个对象是否是Iterator对象:

 1 from collections.abc import Iterator
 2 
 3 # 列表不是迭代器
 4 print(isinstance([],Iterator))
 5 
 6 #字典不是迭代器
 7 print(isinstance({}, Iterator))
 8 
 9 #字符串不是迭代器
10 print(isinstance('abc',Iterator))
11 
12 #for循环是迭代器
13 print((x for x in range(10)), Iterator)
14 
15 
16 #result
17 False
18 False
19 False
20 <generator object <genexpr> at 0x108d3da98> <class 'collections.abc.Iterator'>

listdictstrIterable变成Iterator可以使用iter()函数:

1 from collections.abc import Iterator
2 print(isinstance(iter([]), Iterator))
3 print(isinstance(iter('abc'), Iterator))
4 print(isinstance(iter({}), Iterator))
5 
6 #result
7 True
8 True
9 True

 例如,将列表a转化成迭代器

 1 a=[1,2,3]
 2 a1=iter(a)
 3 print(a1.__next__())
 4 print(a1.__next__())
 5 print(a1.__next__())
 6 print(a1.__next__())
 7 
 8 #result
 9 1
10 2
11 3
12 Traceback (most recent call last):
13   File "/Users/shang/PycharmProjects/AceExercise/day4/Iterator.py", line 46, in <module>
14     print(a1.__next__())
15 StopIteration

  内心小疑问:为什么listdictstr等数据类型不是Iterator

  老实说:这是因为Python的Iterator对象表示的是一个数据流,Iterator对象可以被next()函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration错误。可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度,只能不断通过next()函数实现按需计算下一个数据,所以Iterator的计算是惰性的,只有在需要返回下一个数据时它才会计算。

  Iterator甚至可以表示一个无限大的数据流,例如全体自然数。而使用list是永远不可能存储全体自然数的。

小结:

凡是可作用于for循环的对象都是Iterable类型;

凡是可作用于next()函数的对象都是Iterator类型,它们表示一个惰性计算的序列;

集合数据类型如listdictstr等是Iterable但不是Iterator,不过可以通过iter()函数获得一个Iterator对象。

Python的for循环本质上就是通过不断调用next()函数实现的,例如:

1 for x in [1,2,3,4]:
2     print(x)

实际上完全等价于:

 1 # 首先获得Iterator对象:
 2 it = iter([1, 2, 3, 4, 5])
 3 # 循环:
 4 while True:
 5     try:
 6         # 获得下一个值:
 7         x = next(it)
 8         print(x)
 9     except StopIteration:
10         # 遇到StopIteration就退出循环
11         break

 4、内置参数                              

内置参数详解:https://docs.python.org/3/library/functions.html?highlight=built#ascii

  1 #内置参数
  2 
  3 #绝对值abs(x)
  4 print(abs(-1))
  5 
  6 #all(iterable)
  7 #非0则为真
  8 print(all([1,-2,3]))
  9 print(all([0]))
 10 
 11 #any(iterable)
 12 #只要非空和0则为真
 13 print(any([]))
 14 print(any([0]))
 15 print(any([1,2]))
 16 
 17 #ascii(object)
 18 #没什么用,直接忽视
 19 
 20 #bin(x)
 21 print(bin(4))
 22 #把数字转成二进制,用0b开头
 23 
 24 #class bool([x]) 布尔值,真为true,假为false
 25 print(bool(0))
 26 
 27 
 28 #class bytearray([source[, encoding[, errors]]])
 29 a=bytes('abcde',encoding='utf-8')
 30 print(a) #打印字节格式
 31 print(a.capitalize(),a)   #a.capitalize() 相当于重新生成一个新的二进制字节
 32 #字符串不可以修改,二进制的字节格式更不可以修改
 33 b=bytearray('abcde',encoding='utf-8')
 34 print(b[0])  #打印a的ascii值
 35 b[0]=98     #将a的调整城b,赋值必须输入的是ascii值
 36 print(b)     #改变原二进制的内容
 37 
 38 
 39 #callable(object) 是否可调用的意思
 40 print(callable([]))   #[]不可以被调用
 41 #可以加()都是可以调用的
 42 def func(): pass
 43 print(callable(func))  #函数可以被调用
 44 
 45 
 46 # chr(i)  该ascii值对应的字符
 47 print(chr(97))
 48 #ord(i)   该字符对应的ascii值
 49 print(ord('a'))
 50 
 51 
 52 #@classmethod  后期再展开
 53 
 54 #compile(source, filename, mode, flags=0, dont_inherit=False, optimize=-1)
 55 code='for i in range(10):print(i)'
 56 c=compile(code,'','exec')
 57 exec(c)
 58 code2='1+3*10/2'
 59 d=compile(code2,'','eval')
 60 print(eval(code2))  #可以执行code
 61 print(eval(d))
 62 #该方式相当于import,将外部函数使用字符串的形式传递给code,然后编译并执行code
 63 code='''
 64 def fib(num):
 65     n,a,b=0,0,1
 66     while n<num:
 67         print(b)
 68         a,b=b,a+b
 69         n=n+1
 70     return '已撸完'
 71 
 72 f=fib(10)
 73 '''
 74 exec(code) #可以不进行编译,直接执行
 75 
 76 #class complex([real[, imag]]) 复数
 77 
 78 #delattr(object, name) 面向对象时再展开
 79 
 80 #dir([object])
 81 arr=[]
 82 print(dir(arr)) #打印列表可用的方法
 83 
 84 #divmod(a, b)
 85 print(divmod(5,3)) #(1,2) 1为余数,2为商
 86 
 87 # filter(function, iterable)
 88 #前置:匿名函数
 89 cal=lambda i:print(i)
 90 cal(5)
 91 cal2=lambda n:3 if n<4 else n
 92 print(cal2(6))
 93 #匿名函数只能处理三元运算,不能处理复杂的运算
 94 #filter可以从一组数据中过滤出想要的数据
 95 data=filter(lambda n:n>5,range(10)) #data为迭代器
 96 for i in data:
 97     print(i)
 98 
 99 #map 将参数按照计算规则进行运算
100 data2=map(lambda n:n*n,range(10))
101 for i in data2:
102     print(i)
103 
104 #reduce
105 import functools
106 data3=functools.reduce(lambda x,y:x+y,range(10))
107 print(data3) #将参数循环运算,此处时1+2+3+...+10赋值给data3
108 
109 # class frozenset([iterable])
110 # 将集合变为不可编辑的状态
111 
112 #getattr(object, name[, default])  后期再展开
113 print(globals()) #当前文件所有变量key-value的字典
114 
115 #hex(x)
116 #将数字转换成16进制
117 print(hex(15))
118 
119 #oct 将数据转换成8进制
120 print(oct(8))
121 
122 #len(s) 长度
123 data4=[1,2,3,4]
124 print(len(data4))
125 
126 #round 精度,默认精度为整数
127 print(round(3.1415926))
128 print(round(3.1415926,4))
129 
130 dict2={1:2,3:5,10:-3,-5:22,-10:1}
131 print(sorted(dict2.items()))#默认按照key从小到大,进行排序
132 print(sorted(dict2.items(),key=lambda x:x[1]))  #按照value的从小到大排序
133 
134 
135 #zip  组合
136 data5=[1,2,3,4,5]
137 data6=['a','b','c','d']
138 for i in zip(data5,data6):
139     print(i) #按照数据少的数组来组合
内置参数解码

5、json & pickle 模块                                          

用于序列化的两个模块

  • json,用于字符串 和 python数据类型间进行转换
  • pickle,用于python特有的类型 和 python的数据类型间进行转换

Json模块提供了四个功能:dumps、dump、loads、load

pickle模块提供了四个功能:dumps、dump、loads、load

 

需求:

当特定时间节点时,需将系统相关信息进行镜像,此时将相关的信息保存成Json的格式;当需要系统镜像信息进行重新读取和使用的时,可以实现正常获取

使用josn的序列化和反序列操作

  • json序列化
 1 import json #引用json模块
 2 
 3 info={
 4     'name':'Ace',
 5     'age':29
 6 }
 7 
 8 f=open('Json.text','w')
 9 f.write(json.dumps(info))  #序列化使用dumps
10 f.close()
11 
12 #result
13 #创建json.text文件,并将info信息以字符串形式存储
  • json反序列化
1 import json
2 
3 f=open('Json.text','r')
4 data=json.loads(f.read())
5 print(data['age'])
6 
7 #result
8 29
json是用来不同程序之间的数据交互
json将逐渐取代xml进行数据交互主流方式

但是json无法处理复杂的功能,例如:

 1 import json #引用json模块
 2 
 3 def sayhi(name):
 4     print(name)
 5 
 6 info={
 7     'name':'Ace',
 8     'age':29,
 9     'func':sayhi
10 }
11 
12 #序列化
13 f=open('Json.text','w')
14 f.write(json.dumps(info))  #序列化使用dumps
15 f.close()
16 
17 
18 #反序列化
19 f=open('Json.text','r')
20 data=json.loads(f.read())
21 print(data['age'])
View Code

运行代码时报错:Object of type function is not JSON serializable

为解决这个问题,需要使用pickle模块,但是java无法识别pickle的序列化

  • pickle序列化和反序列化
 1 import pickle
 2 
 3 def sayhi(name):
 4     print(name)
 5 
 6 info={
 7     'name':'Ace',
 8     'age':29,
 9     'func':sayhi
10 }
11 
12 #序列化
13 f=open('Json.text','wb') #wb使用字节的方式进行操作
14 f.write(pickle.dumps(info))  #序列化使用dumps
15 f.close()
16 
17 
18 #反序列化
19 f=open('Json.text','rb')
20 data=pickle.loads(f.read())
21 print(data['age'])
22 print(data['func']('Ace'))
23 
24 
25 #result
26 29
27 Ace
28 None
View Code

  备注:其中pickle许列化的的数据格式为字节格式,另外,没明白sayhi函数执行完结果中None代表的什么含义??

  dump和load的用法

 1 import pickle
 2 
 3 def sayhi(name):
 4     print(name)
 5 
 6 info={
 7     'name':'Ace',
 8     'age':29,
 9     'func':sayhi
10 }
11 
12 #序列化
13 f=open('Json.text','wb') #wb使用字节的方式进行操作
14 
15 #f.write(pickle.dumps(info))  #序列化使用dumps
16 pickle.dump(info,f)
17 
18 f.close()
19 
20 
21 #反序列化
22 f=open('Json.text','rb')
23 
24 #data=pickle.loads(f.read())
25 data=pickle.load(f)
26 
27 print(data['age'])
28 print(data['func']('Ace'))
View Code

   需求:多次挂起(序列化),多次读取(反序列化)

 1 import json
 2 
 3 info={
 4     'name':'Ace',
 5     'age':29
 6 }
 7 
 8 #序列化
 9 f=open('Json.text','w')
10 
11 json.dump(info,f)
12 
13 info['age']=30
14 json.dump(info,f) #实现二次序列化,在text文件中,新增另外记录
15 
16 f.close()
View Code

  python3.0是可以实现多次序列化

 1 import json
 2 
 3 info={
 4     'name':'Ace',
 5     'age':29
 6 }
 7 
 8 #反序列化
 9 f=open('Json.text','r')
10 data=json.load(f)
11 print(data['age'])
12 
13 f.close()
14 
15 #result
16 程序报错,当多次序列化之后,无法再实现反序列化
View Code

  结论:只能一次挂起+一次读取,不能连续多次挂起和多次读取

转载于:https://www.cnblogs.com/ace722/p/9552106.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值