1.json模块

1)json模块方法

①json.dumps()

②json.loads()

③json.dump()

④json.load()

2)json格式的限制

①json格式的key必须是字符串数据类型,如果是数字为key,那么dump之后会强行转成字符串数据类型

import json
dic = {1:2,3:4}
str_dic = json.dumps(dic)
print(str_dic)
new_dic = json.loads(str_dic)
print(new_dic)
输出:
{"1": 2, "3": 4}
{'1': 2, '3': 4}
View Code

②json支持元组作为value,但是对元组做value的字典会把元组强制转化为列表

import json
dic = {"abc":(1,2,3,4)}
str_dic = json.dumps(dic)
print(str_dic)
new_dic = json.loads(str_dic)
print(new_dic)
输出:
{"abc": [1, 2, 3, 4]}
{'abc': [1, 2, 3, 4]}
View Code

注:json不支持元组作为key,因为json只支持字符串数据类型作为json的key

③json格式中的字符串只能是双引号的,如果是单引号会报错

import json
lst = ['123',"abc","27.58","ccc"]
with open('json_test','w') as f:
    json.dump(lst,f)
文件内容:
["123", "abc", "27.58", "ccc"]
View Code

#读取文件内容

import json
lst = ['123',"abc","27.58","ccc"]
with open('json_test','w') as f:
    json.dump(lst,f)
with open('json_test','r') as f:
    ret = json.load(f)
    print(ret)
输出:
['123', 'abc', '27.58', 'ccc']
View Code

注:若手动将json文件中的字符串改为单引号,读取文件内容就会报错

④可以多次的dump数据到文件中,但是不能将多次dump到文件中的内容load出来,因为是多种不同的数据类型了(即时dump的是多个列表)

import json
lst = ['123',"abc","27.58","ccc"]
dic = {"a":"xyz","b":"jdk"}
with open('json_test','w') as f:
    json.dump(lst,f)
    json.dump(dic,f)
文件内容:
["123", "abc", "27.58", "ccc"]{"b": "jdk", "a": "xyz"}
View Code

#dump多次后,load读取文件会出错

import json
lst = ['123',"abc","27.58","ccc"]
dic = {"a":"xyz","b":"jdk"}
with open('json_test','w') as f:
    json.dump(lst,f)
    json.dump(dic,f)
with open('json_test','r') as f:
    ret = json.load(f)
    print(ret)
报错:
json.decoder.JSONDecodeError: Extra data: line 1 column 31 (char 30)
View Code

⑤若要想dump多个数据进入文件,可以使用dumps,

#先将dumps的每一行数据之后,加一个换行符

import json
lst = ['123',"abc","27.58","ccc"]
dic = {"a":"xyz","b":"jdk"}
with open("json_test",'w') as f:
    str_lst = json.dumps(lst)
    str_dic = json.dumps(dic)
    f.write(str_lst+'\n')
    f.write(str_dic+'\n')
文件内容:
["123", "abc", "27.58", "ccc"]
{"a": "xyz", "b": "jdk"}
View Code

#再将文件中的每一行内容loads出来

import json
with open("json_test",'r') as f:
    for line in f:
        ret = json.loads(line)
        print(ret)
输出:
['123', 'abc', '27.58', 'ccc']
{'a': 'xyz', 'b': 'jdk'}
View Code

⑥对于中文格式的key,在文件默认存储的是bytes的类型,若想要保存在文件中也是中文,可以使用参数ensure_ascii = Fasle,(通过loads读取出来的还是中文)

import json
dic = {"name":"阿狸",'age':18,'sex':""}
ret = json.dumps(dic)
res = json.dumps(dic,ensure_ascii=False)
print(ret)
print(res)
dic_new = json.loads(ret)
print(dic_new)
输出:
{"age": 18, "sex": "\u5973", "name": "\u963f\u72f8"}
{"age": 18, "sex": "", "name": "阿狸"}
{'age': 18, 'name': '阿狸', 'sex': ''}
View Code

3)json的其他参数

#为了用户看的方便,可以使用一些参数,但是会浪费存储空间

import json
dic = {"name":['九尾妖狐','阿狸'],'age':18,'sex':""}
ret = json.dumps(dic,sort_keys=True,indent=4,separators=(',',':'),ensure_ascii=False)
print(ret)
输出:
{
    "age":18,
    "name":[
        "九尾妖狐",
        "阿狸"
    ],
    "sex":""
}
View Code

注:set集合数据类型是直接不能序列化的,即json是不允许存储set集合的(set不能被dump以及dumps)

2.pickle模块

       json处理的数据类型是有限的,此时可以使用pickle,但是pickle只有python语言可以识别

1)无论是什么数据类型,使用pickle进行dumps都不会报错,但是会转化为bytes类型,而且只支持转化为bytes类型(解码也不好使)

import pickle
dic = {1:('a','b','c'),(1,2,3):"xyz"}
pic_dit = pickle.dumps(dic)
print(pic_dit)
b'\x80\x03}q\x00(K\x01X\x01\x00\x00\x00aq\x01X\x01\x00\x00\x00bq\x02X\x01\x00\x00\x00cq\x03\x87q\x04K\x01K\x02K\x03\x87q\x05X\x03\x00\x00\x00xyzq\x06u.'
View Code

#使用pickle.loads()可以使原来的数据类型原封不动的恢复

import pickle
dic = {1:('a','b','c'),(1,2,3):"xyz"}
pic_dit = pickle.dumps(dic)           #bytes类型
new_dic = pickle.loads(pic_dit)
print(new_dic)
输出:
{1: ('a', 'b', 'c'), (1, 2, 3): 'xyz'}
View Code

注:只要通过pickle序列化后,就是bytes数据类型了,人类无法认识

使用场景:如果存一写数据,只是为了方便用户去看,就不要使用pickle序列化为bytes类型,而是保存为正常的文字状态;若是为了将一个数据类型存入文件,下次通过程序读出来的还是原来的数据类型,可以使用pickle

2)pickle支持几乎所有的对象

①pickle可以对类的对象进行序列化

import pickle
class Student:
    def __init__(self,name,age,sex):
        self.name = name
        self.age = age
        self.sex = sex
s1 = Student("阿狸",18,"")
print(pickle.dumps(s1))
输出:
b'\x80\x03c__main__\nStudent\nq\x00)\x81q\x01}q\x02(X\x03\x00\x00\x00ageq\x03K\x12X\x03\x00\x00\x00sexq\x04X\x03\x00\x00\x00\xe5\xa5\xb3q\x05X\x04\x00\x00\x00nameq\x06X\x06\x00\x00\x00\xe9\x98\xbf\xe7\x8b\xb8q\x07ub.'
View Code

#通过loads再将序列化的数据类型进行反序列化

import pickle
class Student:
    def __init__(self,name,age,sex):
        self.name = name
        self.age = age
        self.sex = sex
s1 = Student("阿狸",18,"")
ret = pickle.dumps(s1)
reverse_ret = pickle.loads(ret)
print(reverse_ret.name,reverse_ret.age,reverse_ret.sex)
输出:
阿狸 18 女
View Code

②以存入文件或从文件读取的方式对数据进行序列化或反序列化(使用pickle打开文件或读取文件必须是以wb或rb的方式,因为序列化后的数据类型为bytes)

class Student:
    def __init__(self,name,age,sex):
        self.name = name
        self.age = age
        self.sex = sex
s1 = Student("阿狸",18,"")
import pickle
with open("pickle_demo","wb") as f :
    pickle.dump(s1,f)
with open("pickle_demo",'rb') as f:
    ret = pickle.load(f)
    print(ret.name,ret.age,ret.sex)
输出:
阿狸 18 女
View Code

 注:对于如上程序要想正常的将文件中的内容反序列化出来,类必须存在,否则会报错(即对于对象的序列化需要这个对象对应的类在内存中)

应用场景:picke的dump和load非常适合游戏的读档和存档

3)通过pickle向文件dump多个值,并且load多个值出来

with open("pickle_demo","wb") as f:
    pickle.dump({"a":"1"},f)
    pickle.dump({"b":"2"},f)
    pickle.dump({"c":"3"},f)
    pickle.dump({"d":"4"},f)
with open("pickle_demo","rb") as f:
    while True:
        try:
            print(pickle.load(f))
        except EOFError:
            break
输出:
{'a': '1'}
{'b': '2'}
{'c': '3'}
{'d': '4'}
View Code

4)总结

①dump的结果是bytes,dump用的文件句柄需要以wb的形式打开,load用的文件句柄是rb模式

②pickle几乎支持所有对象的序列化

③对于对象的序列化需要这个对象对应的类在内存中

④对于多次dump和load的操作做了良好的处理

3.shelve模块(了解)

1)方法:shelve只提供一个方法open

import shelve
f = shelve.open("shelve.demo")  #创建出三个文件
f['key'] = {'a': {1,2,3},'b':"xyz",'c':"阿狸"}
f.close()

f = shelve.open("shelve.demo")
content = f['key']
f.close()
print(content) #虽然关闭了文件,但是文件内容读取到了内存中
输出:
{'a': {1, 2, 3}, 'c': '阿狸', 'b': 'xyz'}
View Code

 

 

 

2)shelve存到文件中的key,可以以字典的方式直接获取到,不需要像json或者pickle一样一个一个取出来,操作f,就类似操作字典一样

3)适用场景:如果写定了一个文件,改动的比较少,读文件的操作比较多,且大部分的读取都需要基于某个key获得某个value此时可以使用shelve

4)shelve在使用时会有很多限制或问题,尽量不用

总结:一般情况使用json; 如果需要频繁的保存某些状态,用pickle;如果频繁的取某些数据且需要某个key去获取value,可以使用shelve

4.hashlib模块

1)作用:hashlib模块提供了摘要算法,能够把字符串数据类型的变量转化为定长的密文的字符串,且字符串中每一个字符都是一个十六进制数字(字符串可转化为密文,但是密文不可转化为字符串,即不可逆)

2)摘要算法:对于同一个字符串,用相同的算法、相同的手段进行摘要,获得的值总是相同的

3)应用场景:登录的密文验证

#对于同一个字符串,不管这个字符串有多长,只要是相同的,无论在任何环境下,多少次执行,在任何语言中使用相同的算法、相同的手段得到的结果都是相同的;只要不是相同的算法/相同的手段得到的结果一定是不同的;只要不是相同的字符串、得到的结果一定不同

①md5算法

#md5得到的结果是一个32位的字符串,每个字符都是一个16进制

import hashlib
s = "zelasi001"
md5_obj = hashlib.md5() #实例化一个对象
md5_obj.update(s.encode("utf-8")) #必须进行转码
ret = md5_obj.hexdigest()
print(ret, type(ret))
输出:
1e7ac35d19a1cab79d5afdf586705c73 <class 'str'>
View Code

②sha1算法的结果是一个40位的字符串,每个字符串都是一个16进制

#sha1算法

import hashlib
s = "zelasi001"
md5_obj = hashlib.sha1() #实例化一个对象
md5_obj.update(s.encode("utf-8")) #必须进行转码
ret = md5_obj.hexdigest()
print(ret,type(ret))
输出:
1e79f4ae7d434c9dc0142ee303a11826378bbc20 <class 'str'>
View Code

md5算法相比与sha1算法较简单,并且计算速度也较快(效率快);对于sha1算法,若计算的字符串较长,则计算速度慢,但是也更安全(安全不是因为算法本身的问题,而是用的人多,有人进行状况撞库)

注:可以使用加盐的方式,让md5方式变的安全

#盐可以是任意的字符串,只要代码不泄露,则就相对安全

import hashlib
s = "zelasi001"
md5_obj = hashlib.md5("盐可以是任意字符串".encode("utf-8")) #加盐
md5_obj.update(s.encode("utf-8")) #必须进行转码
ret = md5_obj.hexdigest()
print(ret,type(ret))
输出:
49f0ed7a8df8ecd429f18754d609d647 <class 'str'>
View Code

注:即时以上述方式加盐也不安全,因为当用户密码一样,而同一个程序的盐又是相同的,那么加密后的字符串也是相同的,可以使用动态加盐的方式解决上述问题,即使用一个变量做为盐,如用户名

import hashlib
username = input("请输入用户名:")
passwd = input("请输入密码:")
md5_obj = hashlib.md5(username.encode("utf-8"))
md5_obj.update(passwd.encode("utf-8"))
ret = md5_obj.hexdigest()
print(ret)
输出:
请输入用户名:ali
请输入密码:123456
c6cd1bcd66d1a3c10eee458e7eeab759
View Code

4)应用场景:文件的一致性校验

#只要文件内容不变,则md5结构不变

import hashlib
md5_obj = hashlib.md5()
with open("t1.txt","rb") as f:
    md5_obj.update(f.read())
    ret = md5_obj.hexdigest()
    print(ret)
md5_obj = hashlib.md5()
with open("t1_bak.txt","rb") as f:
    md5_obj.update(f.read())
    ret = md5_obj.hexdigest()
    print(ret)
输出:
aaa3f8e2e04da70a23312f477e8f18c4
aaa3f8e2e04da70a23312f477e8f18c4
View Code

#如果这个文件特别大,内存装不下,此时可以按照字节读,可以对一个字符串的某个阶段分别update,得出的结果一致

import hashlib
md5_obj = hashlib.md5()
md5_obj.update("我爱北京天安门".encode())
print(md5_obj.hexdigest())

md5_obj = hashlib.md5()
md5_obj.update("我爱".encode())
md5_obj.update("北京".encode())
md5_obj.update("天安门".encode())
print(md5_obj.hexdigest())
输出:
4ae8f86d04e104db37c9d89736ec35f1
4ae8f86d04e104db37c9d89736ec35f1
View Code

5)对一个大文件进行校验

思路:写一个函数,计算文件的两个md5值,参数:文件1的路径,文件2的路径,默认参数=文件字节数(如1024),返回它们的一致性结果

5.configpaser模块

       有一个固定格式的配置文件,用一个对应的模块去帮你做这个文件的字符串处理,即模块configpaser模块

1)该模块适用于配置文件的格式与windows ini文件类似,可以包含一个或多个节,每个节可以有多个参数(键=值)

注:每一个写在中括号中的值都是一个section,写在每个section下面的叫做option

 

 

 

2)所有的配置必须放置在一个分组中,分组名可以随便起,格式如下,只有写成类似的配置文件格式,才能被模块configpaser处理

setting.ini
[path]
userinfog_path =E:\python\project\untitled\练习\userinfo
userinfog_path =E:\python\project\untitled\练习\passwd
View Code

3)[DEFAULT]组为一个全局的组,其他组都能拿到[DEFAULT]的内容,其他组的option只包含在当前的组中

6.logging模块

1)功能:

①能做到日志格式的的规划

②操作的简化

③日志的分级管理

2)logging不能做的功能

①不能自动生成你要打印的内容

②要程序员自己在开发的时候定义好在那些地方需要打印,要打印的内容是什么,以及内容的级别

3)logging模块的使用

①普通配置型:简单的,可定制化差

②对象配置型:复杂的,可定制化强

4)日志级别

critical>error>warning>info>debug

import logging
logging.debug("Debug Message")     #调试模式
logging.info("Info Message")         #基础信息模块
logging.warning("Warning Message") #警告
logging.error("Error Message")      #错误
logging.critical("Critical Message")   #严重错误
输出:
WARNING:root:Warning Message
ERROR:root:Error Message
CRITICAL:root:Critical Message
日志级别:用户:打印内容
View Code

注:logging模块默认只输出警告级别(warning)及以上的错误信息

#普通配置型(basicConfig)操作日志文件

①修改logging日志模块打印的默认级别

import logging
logging.basicConfig(level=logging.DEBUG)
logging.debug("Debug Message")
logging.info("Info Message")
logging.warning("Warning Message")
logging.error("Error Message")
logging.critical("Critical Message")
输出:
DEBUG:root:Debug Message
INFO:root:Info Message
WARNING:root:Warning Message
ERROR:root:Error Message
CRITICAL:root:Critical Message
View Code

②自定义logging模块日志输出的级别、格式、时间格式

import logging
logging.basicConfig(level=logging.INFO,
                    format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
                    datefmt='%a, %d %b %Y %H:%M:%S')
logging.debug("Debug Message")
logging.info("Info Message")
logging.warning("Warning Message")
logging.error("Error Message")
logging.critical("Critical Message")
输出:
Sat, 28 Nov 2020 16:14:45 基础代码练习.py[line:2798] INFO Info Message
Sat, 28 Nov 2020 16:14:45 基础代码练习.py[line:2799] WARNING Warning Message
Sat, 28 Nov 2020 16:14:45 基础代码练习.py[line:2800] ERROR Error Message
Sat, 28 Nov 2020 16:14:45 基础代码练习.py[line:2801] CRITICAL Critical Message
View Code

③将打印的日志输出到文件(通过参数filename实现)

import logging
logging.basicConfig(level=logging.INFO,
                    format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
                    datefmt='%a, %d %b %Y %H:%M:%S',
                    filename="test.log")
logging.debug("Debug Message")
logging.info("Info Message")
logging.warning("Warning Message")
logging.error("Error Message")
logging.critical("Critical Message")
View Code

注:普通配置型(basicConfig)不能将日志信息即输出到屏幕又输出到文件

例:

import logging
logging.basicConfig(level=logging.INFO,
                    format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
                    datefmt='%a, %d %b %Y %H:%M:%S')
class Manager:
    def __init__(self,name):
        self.name = name
    def create_student(self):
        stu_name = input("学生姓名:")
        logging.info("%s create a student %s" %(self.name,stu_name))
ali = Manager("阿狸")
ali.create_student()
输出:
学生姓名:劫
Sun, 29 Nov 2020 09:58:09 基础代码练习.py[line:2813] INFO 阿狸 create a student 劫
View Code

#logger对象的形式操作日志文件

①创建一个logger对象

②创建一个文件/屏幕管理操作符

③创建一个日志输出的格式

④文件管理/屏幕管理操作符绑定一个格式

⑤logger对象绑定文件/屏幕管理操作符(不绑定就无法往文件中输入)

import logging
# 创建一个logger对象
logger = logging.getLogger()
# 创建一个文件管理操作符
fh = logging.FileHandler('logger.log',encoding='utf-8')
# 创建一个屏幕管理操作符
sh = logging.StreamHandler()
# 创建一个日志输出的格式
format1 = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')

# 文件管理操作符 绑定一个 格式
fh.setFormatter(format1)
# 屏幕管理操作符 绑定一个 格式
sh.setFormatter(format1)
logger.setLevel(logging.DEBUG)
# logger对象 绑定 文件管理操作符
logger.addHandler(fh)
# logger对象 绑定 屏幕管理操作符
logger.addHandler(sh)

logger.debug('debug message')      # 调试模式
logger.info('我的信息')        # 基础信息
logger.warning('warning message')  # 警告
logger.error('error message')      # 错误
logger.critical('critical message')# 严重错误
输出:
2020-11-29 10:16:01,426 - root - DEBUG - debug message
2020-11-29 10:16:01,426 - root - INFO - 我的信息
2020-11-29 10:16:01,426 - root - WARNING - warning message
2020-11-29 10:16:01,427 - root - ERROR - error message
2020-11-29 10:16:01,427 - root - CRITICAL - critical message
View Code

7.异常处理

1)什么是异常,异常和错误的区别

XXXError为错误,一般是由于代码中比较明显的语法错误造成的,在编译代码就能检测出来

XXXIteration:异常,在执行代码的过程中就引发的异常

2)异常发生之后的效果

       一但在程序中发生异常,程序就不再继续执行了;如果发生的异常对程序的后续执行没有影响,可以处理掉这个异常

4)如何看报错信息

       IndexError为错误类型,整个具体的错误就是一个错误对象,整个错误是属于IndexError这一类的。

       List index out of range为错误的具体提示(出现问题时,可利用该提示百度)

#若程序报很多错误,一般为从上往下数最后一个错误引起的;若是源码报错,可从报错的从下往上开始,找到第一行自己写的代码,这行代码就是出错的代码(一般为该行调用源码,导致源码出错了),源码是不会出错的。

5)最简单的异常处理

编译是不会报错,但是允许程序时出错

#当用户输入字母,或者超出列表数量的值时,就会出错,此时可以处理掉异常

l = ['登录','注册','退出']
for i in enumerate(l,1):
    print(i[0],i[1])
num = int(input("Num:"))
print(l[num-1])
输入:
1 登录
2 注册
3 退出
Num:a
Traceback (most recent call last):
  File "E:/python/project/untitled/练习/基础代码练习.py", line 2845, in <module>
    num = int(input("Num:"))
ValueError: invalid literal for int() with base 10: 'a'
View Code

#处理异常:先抓住异常,然后进行处理(报什么错,在except后就写什么错)

l = ['登录','注册','退出']
for i in enumerate(l,1):
    print(i[0],i[1])
try:
    num = int(input("Num:"))
    print(l[n
um-1])
except ValueError:
    print("请输入一个数字")
输出:
1 登录
2 注册
3 退出
Num:aa
请输入一个数字
View Code

注:但是对于如上的异常处理方式,一次只能处理一个异常,若要异常处理多个异常,可使用多分支异常处理

6)多分支异常处理

l = ['登录','注册','退出']
for i in enumerate(l,1):
    print(i[0],i[1])
try:
    num = int(input("Num:"))
    print(l[num-1])
except ValueError:
    print("请输入一个数字")
except IndexError:
    print("输入的数字无效")
输出:
1 登录
2 注册
3 退出
Num:5
输入的数字无效
View Code

②多分支异常的其他写法

l = ['登录','注册','退出']
for i in enumerate(l,1):
    print(i[0],i[1])
try:
    num = int(input("Num:"))
    print(l[num-1])
except (ValueError,IndexError):
    print("Error")
输出:
1 登录
2 注册
3 退出
Num:5
Error
View Code

注:因为异常有很多种,使用如上方式处理异常,会显得程序很冗长,此时可以使用万能异常

7)万能异常

       因为所有的类都继承了Exception类,所以可以直接使用Exception类处理异常

except Exception as 变量名:

    pass

变量名为错误的对象,可以使用如果只写except Exception无法确定具体是哪个地方出错了

try :
    name
except Exception as e :        #e为变量名
    print(type(e),e,e.__traceback__.tb_lineno)
输出:
<class 'NameError'> name 'name' is not defined 2854
View Code

8)万能异常和多分支异常处理组合使用

       对于可以预料到的异常,需要使用单分支异常去处理,对于无法预料的异常可以使用万能异常包住,保证其不出错

       注:万能异常要放在所有多分支异常的最下面,except的条件是互斥的,即执行了最上面的except.则下面的就不执行了,如果把except Exception放在最上面,则就会把所有的异常在最上面就处理掉了

try :
    name
    [][5]
    import a
except NameError:pass
except IndexError:pass
except ImportError:pass
except Exception as e :pass
View Code

9)异常处理其他机制

#如果try里面的代码顺利执行,就执行else语句

try:
    name = "阿狸"
except NameError:
    print("Error")
else:
    print("正常")
输出:
正常
View Code

#无论如何都会执行finally中的语句,即时在try语句中exit()了程序

try:
    name = "阿狸"
except NameError:
    print("Error")
else:
    print("正常")
    exit()
finally:
    print("执行finally中的语句")
输出:
正常
执行finally中的语句
View Code

#finally用法

如果打开一个文件,但是在打开文件的时候报错了,虽然报错了,但是文件是打开的,需要把文件关掉,即时文件没有处理异常,也可以使用finally的方式把文件关闭

try:
    f = open("file",'w')
    exit()
finally:
    print("执行了finally")
输出:
执行了finally
View Code

注:程序的终端,函数的返回,都不会终端finally的执行,只要程序无论怎么样,都会执行,所以可在finally中做一些资源返回、回收的工作最合适

③主动抛异常(即主动写一个报错),但是借助的是python解释器的异常

try:
    num = int(input(">>>"))
except Exception:
    print("在出现异常之后,做什么事情")
    raise   #原封不动的输出try中抓到的异常
输出:
>>>a
在出现异常之后,做什么事情
Traceback (most recent call last):
  File "E:/python/project/untitled/练习/基础代码练习.py", line 2887, in <module>
    num = int(input(">>>"))
ValueError: invalid literal for int() with base 10: 'a'
View Code

10)自定义异常

class CustomException(Exception):  #自定义的异常类,必须基础Exception类
    def __init__(self,msg):
        self.msg = msg

raise  CustomException("这是一个XXX错误,有XXX问题")   #实例化类,传信息
输出:
Traceback (most recent call last):
  File "E:/python/project/untitled/练习/基础代码练习.py", line 2896, in <module>
    raise  CustomException("这是一个XXX错误,有XXX问题")
__main__.CustomException: 这是一个XXX错误,有XXX问题
View Code

11)断言

       如果某一段代码,必须满足某个必要条件才能执行,,且这个必要条件非常重要,关乎下面程序的执行,可以使用断言

①assert 布尔值

assert True:pass             #如果条件为真,执行下面代码

assert False:pass             #如果条件为假,不执行下面代码

②断言和if的区别是,不需要缩进

注:assert和rais一般在程序源码中出现

异常总结:能通过逻辑规避的错误因该用代码逻辑规避掉,应对对某一句或几句话进行处理;只有在程序最后的最后,为了增加用户体验,在外层添加一个大的异常处理;但是调试程序时,要把这个外层的异常去掉

8.双端队列

1)collections模块:提供了扩展数据类型(即数据类型的扩展模块)

2)队列:先进先出

import queue
q = queue.Queue()
q.put('a')       #往队列中放入值
q.put(1)
q.put((1,2,3))
q.put({'k':"value"})
print(q)    #打印的是一个内存地址,而获取不到数据
print(q.get()) #获取第一个放进去的顺序,get一次,队列中少一个值
print(q.qsize()) #查看队列的大小
输出:
<queue.Queue object at 0x0000026CD3BCB668>
a
3
View Code

适用场景:在排队做事情时,如用户批量访问时,先请求的先处理

3)双端队列:从两边都可取值,越先进去的值越在中间,而取值的时候是从两端往中间取值

from collections import deque
dq = deque()
dq.append(5)
dq.append('xyz')
dq.append((2,4,6))
dq.append({"k":"value"})
print(dq)      #可以直接看到双端队列中的值
print(dq.pop())
print(dq)
输出:
deque([5, 'xyz', (2, 4, 6), {'k': 'value'}])
{'k': 'value'}
deque([5, 'xyz', (2, 4, 6)])
View Code

#其他用法

from collections import deque
dq = deque()
dq.append(5)
dq.append('xyz')
dq.append((2,4,6))
dq.append({"k":"value"})
dq.remove('xyz')        #删除某个固定的值
print(dq)
dq.insert(2,"阿狸")  #在第二个位置插入一个值
print(dq)
dq.appendleft("哈哈")   #在最左边插入一个值
print(dq)
输出:
deque([5, (2, 4, 6), {'k': 'value'}])
deque([5, (2, 4, 6), '阿狸', {'k': 'value'}])
deque(['哈哈', 5, (2, 4, 6), '阿狸', {'k': 'value'}])
View Code

注:双端队列的方法虽然和列表一致,但是在底层的数据结构不一样(双端队列和C语言链表一样);对于remove/insert这样的操作,用双端队列的平均效率比列表高,而在列表根据索引查看某个值的效率要高于双端队列