上节回顾:

1、time:-------时间:时间戳 、字符串、结构化时间

2、collections-----扩展数据类型的模块:可命名元组、有序字典、默认字典、双端列队、计数器

3、sys-----和python解释器打交道的模块

    sys.path:和路径有关,且关系到模块导入相关的路径

    sys.argv:[xxx.py.argv1,argv2],python xxx.py argv1  argv2...

今日内容:

常用模块:

  #random 随机数相关  ***

  #0s 操作系统相关*****

  #序列化

    #json *****

    #pickle****

    #shelve***

#异常处理*****

一、random模块

1、生成随机小数(不重要)

import random
print(random.random())      #生成0-1之间的小数
print(random.uniform(10,12))    #n,m之间的小数
# 0.055019711378065383
# 10.69662552212382
生成随机小数

2、生成随机整数(重要)   

  randint   头尾都有

  randrange 顾头不顾尾

import random
print(random.randint(1,2))#必须是两个参数,规定一个范围[1,2]
print(random.randrange(100))#一个参数
print(random.randrange(1,2))#两个参数[1,2)
print(random.randrange(90,100,2))#三个参数,最后一个是步长
生成随机整数

3、从一个序列中随机选择:

  一个choice

  多个sample

import random
print(random.choice("abc"))
# b
print(random.sample([1,"23",[2,3]],2))
# [1, [2, 3]]
从一个序列中随机选择

4、打乱排序列表  shuffle

应用实例:洗牌,彩票,抽奖,测试一些排序算法

item=[1,2,3,4,5,5]
random.shuffle(item)
print(item)
# [3, 5, 1, 2, 5, 4]
打乱排序列表

面试题:

1、生成一个6位数字随机验证码

import random
l=[]
for i in range(6):
    rand_num=random.randint(0,9)
    l.append(str(rand_num))
print("".join(l))
# 197092
生成一个六位数字随机验证码
import random
print(random.sample(range(0,10),6))
生成6个不重复的数字验证码

重要例子:

生成一个6位数字+字母的验证码

0-9 

a-z  :65-90

A-Z :97-122

方法二:

import random
l=[]
for i in range(6):
    num=str(random.randint(0,9))
    alpha_lower=chr(random.randint(65,90))
    alpha_upper=chr(random.randint(97,122))
    ret=random.choice([num,alpha_lower,alpha_upper])
    l.append(ret)
print("".join(l))
6位数字+字母随机验证码

二、os模块

 照着敲写: os模块是与操作系统交互的一个接口

'''
os.getcwd() 获取当前工作目录,即当前python脚本工作的目录路径
os.chdir("dirname")  改变当前脚本工作目录;相当于shell下cd
os.curdir  返回当前目录: ('.')
os.pardir  获取当前目录的父目录字符串名:('..')
os.makedirs('dirname1/dirname2')    可生成多层递归目录
os.removedirs('dirname1')    若目录为空,则删除,并递归到上一级目录,如若也为空,则删除,依此类推
os.mkdir('dirname')    生成单级目录;相当于shell中mkdir dirname
os.rmdir('dirname')    删除单级空目录,若目录不为空则无法删除,报错;相当于shell中rmdir dirname
os.listdir('dirname')    列出指定目录下的所有文件和子目录,包括隐藏文件,并以列表方式打印
os.remove()  删除一个文件
os.rename("oldname","newname")  重命名文件/目录
os.stat('path/filename')  获取文件/目录信息
os.sep    输出操作系统特定的路径分隔符,win下为"\\",Linux下为"/"
os.linesep    输出当前平台使用的行终止符,win下为"\t\n",Linux下为"\n"
os.pathsep    输出用于分割文件路径的字符串 win下为;,Linux下为:
os.name    输出字符串指示当前使用平台。win->'nt'; Linux->'posix'
os.system("bash command")  运行shell命令,直接显示
os.popen("bash command)  运行shell命令,获取执行结果
os.environ  获取系统环境变量

os.path
os.path.abspath(path) 返回path规范化的绝对路径 os.path.split(path) 将path分割成目录和文件名二元组返回 os.path.dirname(path) 返回path的目录。其实就是os.path.split(path)的第一个元素 os.path.basename(path) 返回path最后的文件名。如何path以/或\结尾,那么就会返回空值。
                        即os.path.split(path)的第二个元素
os.path.exists(path)  如果path存在,返回True;如果path不存在,返回False
os.path.isabs(path)  如果path是绝对路径,返回True
os.path.isfile(path)  如果path是一个存在的文件,返回True。否则返回False
os.path.isdir(path)  如果path是一个存在的目录,则返回True。否则返回False
os.path.join(path1[, path2[, ...]])  将多个路径组合后返回,第一个绝对路径之前的参数将被忽略
os.path.getatime(path)  返回path所指向的文件或者目录的最后访问时间
os.path.getmtime(path)  返回path所指向的文件或者目录的最后修改时间
os.path.getsize(path) 返回path的大小

 例子:

查看文件的最后修改时间

import os
import time   
ret=os.path.getmtime(r"C:/Users/Administrator/PycharmProjects/start/练习题/练习11.py")
print(time.strftime("%x %X",time.localtime(ret)))
# 12/14/17 11:43:07
查看文件的最后修改时间

其余的具体操作查看   有道笔记

三、序列化处理模块

什么叫序列化——将原本的字典、列表等内容转换成一个字符串的过程就叫做序列化

比如,我们在python代码中计算的一个数据需要给另外一段程序使用,那我们怎么给?
现在我们能想到的方法就是存在文件里,然后另一个python程序再从文件里读出来。
但是我们都知道,对于文件来说是没有字典这个概念的,所以我们只能将数据转换成字典放到文件中。
你一定会问,将字典转换成一个字符串很简单,就是str(dic)就可以办到了,为什么我们还要学习序列化模块呢?
没错序列化的过程就是从dic 变成str(dic)的过程。现在你可以通过str(dic),将一个名为dic的字典转换成一个字符串,
但是你要怎么把一个字符串转换成字典呢?
聪明的你肯定想到了eval(),如果我们将一个字符串类型的字典str_dic传给eval,就会得到一个返回的字典类型了。
eval()函数十分强大,但是eval是做什么的?e官方demo解释为:将字符串str当成有效的表达式来求值并返回计算结果。
BUT!强大的函数有代价。安全性是其最大的缺点。
想象一下,如果我们从文件中读出的不是一个数据结构,而是一句"删除文件"类似的破坏性语句,那么后果实在不堪设设想。
而使用eval就要担这个风险。
所以,我们并不推荐用eval方法来进行反序列化操作(将str转换成python中的数据结构)

序列化的目的

1、在传输过程尽量少使用eval

s_dic=str({"k":"v"})
print(repr(s_dic))
print(repr(eval(s_dic)),type(eval(s_dic)))
# "{'k': 'v'}"
# {'k': 'v'} <class 'dict'>

2、json的优点:所有语言都通用,它能序列化的数据是有限的:字典列表元组

      序列化中的内容只能包含:字典、列表、数字、字符串。如果是元组——自动转成列表的样子

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

(1)dumps和loads与字符串打交道

import json
ret=json.dumps({"k":[1,2,3]})
print(repr(ret),type(ret))
ret2=json.loads(ret)
print(repr(ret2),type(ret2))
# '{"k": [1, 2, 3]}' <class 'str'>
# {'k': [1, 2, 3]} <class 'dict'>
dumps与loads

(2)dump 与load是与文件打交道的,一次性只能读出来一个列表或者一个字典

  解决这个问题是使用for循环读出用loads将字符串转成列表

import json
# f=open("json_file","a")
# json.dump({"k":"v"},f)
# f.close()
with open("json_file")as f:
    ret=json.load(f)
    print(ret,type(ret))   # 一次只能反序列化一个字典
一次只能反序列化一个字典
import json
with open("json_file")as f:
    for line in f:
        print(json.loads(line))
# {'k': 'v'}
# {'k': 'v'}
解决可以一次反序列化多个字典
str=json.dumps(dict)
f.write(str+"\n")

3、pickle 是py特有的

  dumps  loads  dump load   pickle---序列化任何数据类型

   pickle---序列化任何数据类型,python专有的不能和其他语言兼容,结果是bytes

import pickle      #用pickle序列化的数据,反序列化也必须用pickle
ret=pickle.dumps({1,2,3,4})
print(ret)
#序列化的结果是以字节的形式显示出来的,也就是为甚么可以序列化任何数据类型的原因
# b'\x80\x03cbuiltins\nset\nq\x00]q\x01(K\x01K\x02K\x03K\x04e\x85q\x02Rq\x03.'

4、shelve  是python3.6新加入的序列化模块

 

 (1)序列化  写进文件

import shelve
f=shelve.open("shelve_file")
f["key"]={"int":10,"float":9.5,"string":"sample data"}
f.close()
一次写进了三个文件

(2)反序列化

#反序列化
f1=shelve.open("shelve_file")
existing=f1["key"]
f1.close()
print(existing)
#{'int': 10, 'float': 9.5, 'string': 'sample data'}
反序列化文件

(3)这个模块有个限制,它不支持多个应用同一时间往同一个DB进行操作(不支持同一时间向同一个文件中写入)。

  所以当我们知道我们的应用如果进行读,操作,我们可以让shelve通过只读的方式打开DB

   不支持多个人同时写,支持多个人同时读,如果只是读的话,设置flag=“r”

import shelve
f=shelve.open("shelve_file",flag="r")
f["key"]={"int":10,"float":9.5,"string":"Sample data"}#直接对文件句柄操作,就可以存入文件
f.close()
flag="r" 多个人同时读

  正常情况下 shelve打开文件句柄感知不到值的修改,设置writeback=True就可以保存修改内容

import shelve
f1=shelve.open("shelve_file",writeback=True)
print(f1["key"])        #{'int': 10, 'float': 9.5, 'string': 'Sample data'}
f1["key"]["new_value"]="this was not here before"
f1.close()
f1=shelve.open("shelve_file")
exiting=f1["key"]   #取出数据的时候也只需要直接用key获取即可,但是key不存在会报错
print(exiting)   #{'int': 10, 'float': 9.5, 'string': 'Sample data', 'new_value': 'this was not here before'}
f1.close()
writeback=True 保存修改内容

  writeback方式有优点也有缺点。优点是减少了我们出错的概率,并且让对象的持久化对用户更加的透明了;但这种方式并不是所有的情况下都需要,首先,使用writeback以后,shelf在open()的时候会增加额外的内存消耗,并且当DB在close()的时候会将缓存中的每一个对象都写入到DB,这也会带来额外的等待时间。因为shelve没有办法知道缓存中哪些对象修改了,哪些对象没有修改,因此所有的对象都会被写入

  shelve只提供一个open,shelve,open(“文件名”)拿到一个文件句柄,这个文件句柄就可以当做字典的操作

import shelve
f1=shelve.open("shelve_file")
exiting=f1["key"]   #取出数据的时候也只需要直接用key获取即可,但是key不存在会报错
print(exiting)  #{'int': 10, 'float': 9.5, 'string': 'Sample data'}
f1.close()
使用key取用数据

总结:  json:所有语言通用,只能转换的数据类型有限*****

    pickle:只限于Python,能转换所有的数据类型   做游戏的时候使用

    shelve:只限于python语言,能转换所有的数据类型,使用方法类似字典

三、异常处理:

 

 什么是异常:异常发生之后的代码就不执行了

什么是异常处理:python解释器检测到错误,触发异常(也允许程序自己触发异常)

        程序员编写特定的代码,专门用来捕捉这个异常(这段代码与程序逻辑无关,与异常处理有关)

        如果捕捉成功则进入另外一个处理分支,执行你为其定制的逻辑,使程序不会崩溃,这就是异常处理

 

 

 直接跳过了第二个错误的分支

 

只要有一个except符合条件  下面的就不会执行了

万能异常处理:忌讳使用

万能异常处理 应该放在其他的之后

 

总结:

异常处理的补充:

(1)

(2)

(4)

(5)在函数中  return之后仍然执行  finally之后的内容

def func():
    f=open("f","w")
    try:
        for i in range(10):
            f.write(i)
    except Exception:
        print(123)
        return
    finally:
        print("before close")
        f.close()
        print("after close")
func()
# 123
# before close
# after close

 

要注意的问题