第1章 re模块补充
1.1 贪婪匹配:回溯算法
1.2 .*?的用法
1.3 例:分组<name>取值
1.4 匹配整数删除小数
1.5 正则测试地址
第2章 重点模块
2.1 hashlib
2.1.1 调用方法
2.1.2 hashlib.md5()
2.1.3 hashlib.sha1()
2.1.4 加密原则
2.1.5 MD5两个方法
2.1.6 update/hexdigest
2.1.7 密码加盐
2.1.8 动态加盐
2.1.9 校验文件一致性
2.2 configparser
2.2.1 常见文档格式
2.2.2 configparser
2.2.3 ini查看方法
2.2.4 ini增删改
2.3 ****logging
2.3.1 灵活匹配日志级别,输出位置
2.3.2 配置参数
2.3.3 logger对象配置
2.3.4 logger写法
2.4 序列化模块
2.4.1 定义
2.4.2 序列化作用:
2.4.3 反序列化
2.4.4 json
2.4.5 dumps
2.4.6 loads
2.4.7 dump
2.4.8 load
2.4.9 应用小结
2.4.10 ensure_ascii
2.5 pickle
2.5.1 定义
2.5.2 dumps
2.5.3 loads
2.5.4 dump
2.5.5 load
2.5.6 应用小结
2.5.7 load
2.5.8 dumps
2.5.9 loads
2.5.10 try的用法
2.6 shelve
2.6.1 存入
2.6.2 只读
2.6.3 保存
2.7 项目开发规范
第3章 拾遗
3.1 计算文件大小
第1章 re模块补充
1.1 贪婪匹配:回溯算法
l 贪婪匹配:在满足匹配时,匹配尽可能长的字符串,默认情况下,采用贪婪匹配
l 非贪婪匹配:加上?为将贪婪匹配模式转为非贪婪匹配模式,尽可能少的匹配字符串
正则 | 待匹配字符 | 匹配 | 说明 |
<.*> | <script>...<script> | <script>...<script> | 默认为贪婪匹配模式,会匹配尽量长的字符串 |
<.*?> | r'\d' |
<script> | 加上?为将贪婪匹配模式转为非贪婪匹配模式,会匹配尽量短的字符串 |
l 几个常用的非贪婪匹配Pattern
*? 重复任意次,但尽可能少重复
+? 重复1次或更多次,但尽可能少重复
?? 重复0次或1次,但尽可能少重复
{n,m}? 重复n到m次,但尽可能少重复
{n,}? 重复n次以上,但尽可能少重复
1.2 .*?的用法
.是任意字符
*是取0 至无限长度
?是非贪婪模式
注意:合在一起就是取尽量少的任意字符,一般不会单独用,多用在 .*?x (取前面任意长度的字符,直到一个x出现)
1.3 例:分组<name>取值
import re
ret = re.search('<(?P<tag>\w+)>\w+</(?P=tag)>','<h1>hello</h1>')
#还可以在分组中利用?<name>的形式给分组起名字
#获取的匹配结果可以直接用group('名字')拿到对应的值
print(ret)
print(ret.group('tag'))
ret = re.search('<(?P<tag_name>\w+)>\w+</(?P=tag_name)>','<h1>hello</h1>')
print(ret.group('tag_name'))
print(ret.group())
输出:
C:\python3\python3.exe D:/python/untitled2/python_9/lession.py
<_sre.SRE_Match object; span=(0, 14), match='<h1>hello</h1>'>
h1
h1
<h1>hello</h1>
ret = re.search(r"<(\w+)>\w+</\1>","<h1>hello</h1>")
#如果不给组起名字,也可以用\序号来找到对应的组,表示要找的内容和前面的组内容一致
#获取的匹配结果可以直接用group(序号)拿到对应的值
print(ret.group(1))
print(ret.group()) #结果 :<h1>hello</h1>
1.4 匹配整数删除小数
import re
ret=re.findall(r"\d+","1-2*(60+(-40.35/5)-(-4*3))")
print(ret) #['1', '2', '60', '40', '35', '5', '4', '3']
ret=re.findall(r"-?\d+\.\d*|(-?\d+)","1-2*(60+(-40.35/5)-(-4*3))")
输出
print(ret) #['1', '-2', '60', '', '5', '-4', '3']
ret.remove("")
print(ret) #['1', '-2', '60', '5', '-4', '3']
1.5 正则测试地址
网址:http://tool.chinaz.com/regex/
推荐书籍:《正则指引》
第2章 重点模块
2.1 hashlib
解释:数据库密码不能以明文形式存在,一下为加密方法
2.1.1 调用方法
import hashlib
2.1.2 hashlib.md5()
解释:32位16进制的字符串
import hashlib
md5 = hashlib.md5()
s = '123wxd'
md5.update(s.encode('utf-8'))
print(md5)
print(md5.hexdigest())#输出加密的结果
2.1.3 hashlib.sha1()
hashlib.sha256()
解释:40位16进制的字符串加密,后尾跟的数字越大位数越高,但是效率也会降低。
例:
import hashlib
sha1 = hashlib.sha1()
sha1.update('123wxd'.encode('utf-8'))
print(sha1.hexdigest())
输出
C:\python3\python3.exe D:/python/untitled2/python_9/lession.py
2aa0cfa3b6a1296d76ea7d32706826d34c7f0de4
2.1.4 加密原则
l 先考虑安全
l 再考虑效率
2.1.5 MD5两个方法
2.1.6 update/hexdigest
使用方法
update(接bytes类型)
hexdigest()将加密结果输出
加密特点:
l 使用相同的算法对相同一个字符串进行摘要
l 在任意时刻任意平台任意任意语言的结果总是不变的
l 这个摘要过程不可逆
l 对于不同的数据的计算结果总是不同
缺点:
l MD5算法很常用,反解密手段很丰富,一般不再采用
小结:
由此:登录的时候怎么验证不可逆的?
用户输入密码之后,再用相同的算法再摘要一次和数据库的密码进行比对
例1)update
import hashlib
md5 = hashlib.md5()
s = '123wxd'
md5.update(s.encode('utf-8'))
print(md5)
print(md5.hexdigest())#输出加密的结果
输出
C:\python3\python3.exe D:/python/untitled2/python_9/lession.py
<md5 HASH object @ 0x0000000001DFC3C8>
8fac34aeeec531305aee1680ddde0b41
2.1.7 密码加盐
解释:加盐后密码安全更高
例:
import hashlib
md5_obj = hashlib.md5('你猜啊'.encode('utf-8'))
s = input('>>>')
md5_obj.update(s.encode('utf-8'))
print(md5_obj.hexdigest())
输出
C:\python3\python3.exe D:/python/untitled2/python_9/lession.py
>>>123wxd
b359c4fd054a6b4a0435fa796d61ba06
2.1.8 动态加盐
解释:为了更安全使用用户名作为盐
例:
import hashlib
username = input('>>>')
md5_obj = hashlib.md5(username.encode('utf-8'))
pasword = input('>>>')
md5_obj.update(pasword.encode('utf-8'))
print(md5_obj.hexdigest())
输出
C:\python3\python3.exe D:/python/untitled2/python_9/lession.py
>>>wxd
>>>123wxd
4b34a46ca2f3e7bf970ada1151d53704
2.1.9 校验文件一致性
l 小文件校验:
def compare():
with open(r'C:\Users\Administrator\Desktop\发红包.py','rb') as f1,open(r'C:\Users\Administrator\Desktop\发红包bak.py','rb') as f2:
content1 = f1.read()
content2 = f2.read()
md5_obj1 = hashlib.md5()
md5_obj1.update(content1)
md5_obj2 = hashlib.md5()
md5_obj2.update(content2)
return md5_obj1.hexdigest() == md5_obj2.hexdigest()
print(compare())
输出
C:\python3\python3.exe D:/python/untitled2/python_9/lession.py
True
注意:
update只能一个摘要一次,不能用同一个对象摘要多次
import hashlib
md5_obj1 = hashlib.md5()
md5_obj1.update('hello'.encode('utf-8'))
md5_obj1.update('al'.encode('utf-8'))
md5_obj1.update('ex'.encode('utf-8'))
print(md5_obj1.hexdigest())
print(md5_obj1.hexdigest())
输出:
C:\python3\python3.exe D:/python/untitled2/python_9/lession.py
354ca34fd199b3cbcd45a7df7de2c5a6
354ca34fd199b3cbcd45a7df7de2c5a6
l 大文件5G校验:
解释:按照字节来读
import hashlib,os
def get_md5(file,n=1024):
with open(file,'rb') as f1:
md5_obj = hashlib.md5()
file_size = os.path.getsize(file)
while file_size >0:
md5_obj.update(f1.read(n))
file_size -= n
return md5_obj.hexdigest()
def compare(file1,file2):
return get_md5(file1) == get_md5(file2)
print(compare(r'C:\Users\Administrator\Desktop\发红包.py',r'C:\Users\Administrator\Desktop\发红包bak.py'))
输出
C:\python3\python3.exe D:/python/untitled2/python_9/lession.py
True
2.2 configparser
解释:配置文件相关,该模块适用于配置文件的格式与windows ini文件类似,可以包含一个或多个节(section),每个节可以有多个参数(键=值)。
2.2.1 常见文档格式
[DEFAULT]
ServerAliveInterval = 45
Compression = yes
CompressionLevel = 9
ForwardX11 = yes
[bitbucket.org]
User = hg
[topsecret.server.com]
Port = 50022
ForwardX11 = no
2.2.2 configparser
解释:生成ini文件
import configparser
config = configparser.ConfigParser()
config["DEFAULT"] = {'ServerAliveInterval': '45',
'Compression': 'yes',
'Compressionlevel': '9',
'ForwardXll': 'yes',
'file_path': r'D:\python\untitled2\python_9\userinfo'}
config['bitbucket.org'] = {'User': 'hg'}
config['topsecret.server.com'] = {'Host Port': '50022', 'Forwardxll':'no'}
with open('examp.ini', 'w') as configfile:
config.write(configfile)
生成的examp.ini:
[DEFAULT]
serveraliveinterval = 45
compression = yes
compressionlevel = 9
forwardxll = yes
file_path = D:\python\untitled2\python_9\userinfo
[bitbucket.org]
user = hg
[topsecret.server.com]
host port = 50022
forwardxll = no
2.2.3 ini查看方法
import configparser
config = configparser.ConfigParser()
#---------------------------查找文件内容,基于字典的形式
print(config.sections()) # []
config.read('example.ini')
print(config.sections()) # ['bitbucket.org', 'topsecret.server.com']
print('bytebong.com' in config) # False
print('bitbucket.org' in config) # True
print(config['bitbucket.org']["user"]) # hg
print(config['DEFAULT']['Compression']) #yes
print(config['topsecret.server.com']['ForwardX11']) #no
print(config['bitbucket.org']) #<Section: bitbucket.org>
for key in config['bitbucket.org']: # 注意,有default会默认default的键
print(key)
print(config.options('bitbucket.org')) # 同for循环,找到'bitbucket.org'下所有键
print(config.items('bitbucket.org')) #找到'bitbucket.org'下所有键值对
print(config.get('bitbucket.org','compression')) # yes get方法Section下的key对应的value
2.2.4 ini增删改
import configparser
config = configparser.ConfigParser()
config.read('example.ini')
config.add_section('yuan')
config.remove_section('bitbucket.org')
config.remove_option('topsecret.server.com',"forwardx11")
config.set('topsecret.server.com','k1','11111')
config.set('yuan','k2','22222')
config.write(open('new2.ini', "w"))
2.3 ****logging
两种方式可以使用
1、简单配置方式
例:
import logging
logging.debug('debug message')
logging.info('info message')
logging.warning('warning message')
logging.error('error message')
logging.critical('critical message')
输出
C:\python3\python3.exe D:/python/untitled2/python_9/lession.py
WARNING:root:warning message
ERROR:root:error message
CRITICAL:root:critical message
默认情况下Python的logging模块将日志打印到了标准输出中,且只显示了大于等于WARNING级别的日志,这说明默认的日志级别设置为WARNING(日志级别等级CRITICAL > ERROR > WARNING > INFO > DEBUG),默认的日志格式为日志级别:Logger名称:用户输出消息。
默认不打印debug和info的信息
import logging
logging.basicConfig(level=logging.DEBUG,
format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
datefmt='%a, %d %b %Y %H:%M:%S',
filename='/tmp/test.log',
filemode='w')
logging.debug('debug message')
logging.info('info message')
logging.warning('warning message')
logging.error('error message')
logging.critical('critical message')
2.3.1 灵活匹配日志级别,输出位置
import logging
logging.basicConfig(level=logging.DEBUG,
format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
datefmt='%a, %d %b %Y %H:%M:%S',
filename='/tmp/test.log',
filemode='w')
logging.debug('debug message')
logging.info('info message')
logging.warning('warning message')
logging.error('error message')
logging.critical('critical message')
2.3.2 配置参数
logging.basicConfig()函数中可通过具体参数来更改logging模块默认行为,可用参数有:
filename:用指定的文件名创建FiledHandler,这样日志会被存储在指定的文件中。
filemode:文件打开方式,在指定了filename时使用这个参数,默认值为“a”还可指定为“w”。
format:指定handler使用的日志显示格式。
datefmt:指定日期时间格式。
level:设置rootlogger(后边会讲解具体概念)的日志级别
stream:用指定的stream创建StreamHandler。可以指定输出到sys.stderr,sys.stdout或者文件(f=open(‘test.log’,’w’)),默认为sys.stderr。若同时列出了filename和stream两个参数,则stream参数会被忽略。
format参数中可能用到的格式化串:
%(name)s Logger的名字
%(levelno)s 数字形式的日志级别
%(levelname)s 文本形式的日志级别
%(pathname)s 调用日志输出函数的模块的完整路径名,可能没有
%(filename)s 调用日志输出函数的模块的文件名
%(module)s 调用日志输出函数的模块名
%(funcName)s 调用日志输出函数的函数名
%(lineno)d 调用日志输出函数的语句所在的代码行
%(created)f 当前时间,用UNIX标准的表示时间的浮 点数表示
%(relativeCreated)d 输出日志信息时的,自Logger创建以 来的毫秒数
%(asctime)s 字符串形式的当前时间。默认格式是 “2003-07-08 16:49:45,896”。逗号后面的是毫秒
%(thread)d 线程ID。可能没有
%(threadName)s 线程名。可能没有
%(process)d 进程ID。可能没有
%(message)s用户输出的消息
2.3.3 logger对象配置
import logging
logger = logging.getLogger()
# 创建一个handler,用于写入日志文件
fh = logging.FileHandler('test.log',encoding='utf-8')
# 再创建一个handler,用于输出到控制台
ch = logging.StreamHandler()
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
fh.setLevel(logging.DEBUG)
fh.setFormatter(formatter)
ch.setFormatter(formatter)
logger.addHandler(fh) #logger对象可以添加多个fh和ch对象
logger.addHandler(ch)
logger.debug('logger debug message')
logger.info('logger info message')
logger.warning('logger warning message')
logger.error('logger error message')
logger.critical('logger critical message')
注意:
logging库提供了多个组件:Logger、Handler、Filter、Formatter。Logger对象提供应用程序可直接使用的接口,Handler发送日志到适当的目的地,Filter提供了过滤日志信息的方法,Formatter指定日志显示格式。另外,可以通过:logger.setLevel(logging.Debug)设置级别,当然,也可以通过
fh.setLevel(logging.Debug)单对文件流设置某个级别
2.3.4 logger写法
创建一个logger对象
创建一个屏幕管理对象
创建一个管理对象
创建一个格式对象1
创建一个格式化对象2
屏幕管理队像 + 格式化对象1
文件管理队像+ 格式化对象2
logger对象方法
屏幕管理队像
文件管理队像
logger对象调用输出级别
logger队像调用基本信息输出功能
logger对象调用输出错误日志
logger对象调用批判日志信息
例:
import logging
#创建一个logger对象
logger = logging.getLogger()
#创建一个屏幕管理队像
sh = logging.StreamHandler()
#创建一个文件管理队像
fh = logging.FileHandler('test2.log',encoding='utf-8')
#创建一个格式队像1
fomatter = logging.Formatter('%(asctime)s-%(name)s-%(levelname)s-%(message)s')
#创建一个格式队像2
#屏幕管理队像 + 创建一个格式化对象1
sh.setFormatter(fomatter)
#文件管理队像 + 创建一个格式对象2
fh.setFormatter(fomatter)
#logger对象
#屏幕管理队像
logger.addHandler(sh)
#文件管理队像
logger.addHandler(fh)
logger.setLevel(logging.DEBUG)
logger.debug('你好')
logger.info('info messagge')
logger.error('error message')
logger.critical('critical message')
输出
C:\python3\python3.exe D:/python/untitled2/python_9/lession.py
2018-07-11 00:02:56,469-root-DEBUG-你好
2018-07-11 00:02:56,469-root-INFO-info messagge
2018-07-11 00:02:56,469-root-ERROR-error message
2018-07-11 00:02:56,469-root-CRITICAL-critical message
2.4 序列化模块
2.4.1 定义
解释:数据结构转变成字符串的过程叫做序列化
序列:一个有序的结构
例:
list1 = [1,2,3]
print(repr(str(list1)))
输出
C:\python3\python3.exe D:/python/untitled2/python_9/lession.py
'[1, 2, 3]'
2.4.2 序列化作用:
l 文件存储
l 网络传输
l 以某种存储形式使自定义对象持久化;
l 将对象从一个地方传递到另一个地方。
l 使程序更具维护性
2.4.3 反序列化
解释:数据结构转化为字符串的过程
list1 = [1,2,3]
s = (str(list1))
print(repr(eval(s)))
输出
C:\python3\python3.exe D:/python/untitled2/python_9/lession.py
[1, 2, 3]
注意
eval()函数十分强大,但是eval是做什么的?e官方demo解释为:将字符串str当成有效的表达式来求值并返回计算结果。
BUT!强大的函数有代价。安全性是其最大的缺点。
想象一下,如果我们从文件中读出的不是一个数据结构,而是一句"删除文件"类似的破坏性语句,那么后果实在不堪设设想。
而使用eval就要担这个风险。
所以,我们并不推荐用eval方法来进行反序列化操作(将str转换成python中的数据结构)
2.4.4 json
解释:json,用于字符串 和 python数据类型间进行转换
特点
l 所有的语言都通用
l 结果可读
l 数据类型优先
l 网络传输,涉及接口时候用
缺点
l 不适应任意数据类型
2.4.5 dumps
解释:序列化过程
例:
import json
dic = {'k1':'v1','k2':'v2','k3':'v3'}
str_dic = json.dumps(dic) #序列化:将一个字典转换成一个字符串
print(type(str_dic),str_dic) #<class 'str'> {"k3": "v3", "k1": "v1", "k2": "v2"}
#注意,json转换完的字符串类型的字典中的字符串是由""表示的
2.4.6 loads
解释:反序列化过程
例:
dic2 = json.loads(str_dic) #反序列化:将一个字符串格式的字典转换成一个字典
#注意,要用json的loads功能处理的字符串类型的字典中的字符串必须由""表示
print(type(dic2),dic2) #<class 'dict'> {'k1': 'v1', 'k2': 'v2', 'k3': 'v3'}
例:列表序列化和反序列化
list_dic = [1,['a','b','c'],3,{'k1':'v1','k2':'v2'}]
str_dic = json.dumps(list_dic) #也可以处理嵌套的数据类型
print(type(str_dic),str_dic) #<class 'str'> [1, ["a", "b", "c"], 3, {"k1": "v1", "k2": "v2"}]
list_dic2 = json.loads(str_dic)
print(type(list_dic2),list_dic2) #<class 'list'> [1, ['a', 'b', 'c'], 3, {'k1': 'v1', 'k2': 'v2'}]
2.4.7 dump
解释:dump方法接收一个文件句柄,直接将字典转换成json字符串写入文件
import json
f = open('json_file','w')
dic = {'k1':'v1','k2':'v2','k3':'v3'}
json.dump(dic,f)
f.close()
f = open('json_file')
2.4.8 load
解释:load方法接收一个文件句柄,直接将文件中的json字符串转换成数据结构返回
dic2 = json.load(f)
f.close()
print(type(dic2),dic2)
2.4.9 应用小结
l 需要连续dump,使用dumps
l 若10个字典,分别对每一个字典进行dumps转成字符串,写到文件+\n
l 反序列化的时候,先按行读"{}\n",去掉换行符之后使用loads反序列化
import json
lst = [1,2,3]
dic = {'a':1}
ret1 = json.dumps(lst)
ret2 = json.dumps(dic)
print(lst,dic)
print(ret1,ret2)
print(type(ret1),type(ret2))
输出
C:\python3\python3.exe D:/python/untitled2/python_9/lession.py
[1, 2, 3] {'a': 1}
[1, 2, 3] {"a": 1}
<class 'str'> <class 'str'>
l json的要求字典中的key必须是字符串
l jsion 支持有限的数据类型:字典、列表、数字类型
res1 = json.loads(ret1)
res2 = json.loads(ret2)
print(res1,type(res1))
print(res2,type(res2))
输出
[1, 2, 3] <class 'list'>
{'a': 1} <class 'dict'>
l json字典的key只能是字符串
import json
d1 ={(1,2,3):123}
json.dumps(d1)
输出:
C:\python3\python3.exe D:/python/untitled2/python_9/lession.py
Traceback (most recent call last):
File "D:/python/untitled2/python_9/lession.py", line 217, in <module>
json.dumps(d1)
File "C:\python3\lib\json\__init__.py", line 231, in dumps
return _default_encoder.encode(obj)
File "C:\python3\lib\json\encoder.py", line 199, in encode
chunks = self.iterencode(o, _one_shot=True)
File "C:\python3\lib\json\encoder.py", line 257, in iterencode
return _iterencode(o, 0)
TypeError: keys must be a string
2.4.10 ensure_ascii
解释:编码时,显示中文字符
例:
import json
f = open('file','w')
json.dump({'国籍':'中国'},f)
ret = json.dumps({'国籍':'中国'})
f.write(ret+'\n')
json.dump({'国籍':'美国'},f,ensure_ascii=False)# 加上:ensure_ascii=False
ret = json.dumps({'国籍':'美国'},ensure_ascii=False)
f.write(ret+'\n')
f.close()
输出
{"\u56fd\u7c4d": "\u4e2d\u56fd"}{"\u56fd\u7c4d": "\u4e2d\u56fd"}
{"国籍": "美国"}{"国籍": "美国"}
2.5 pickle
解释:
2.5.1 定义
解释:pickle,用于python特有的类型 和 python的数据类型间进行转换
特点
l 结果是bytes
l 只支持python语言
l 几乎支持 所有数据类型
用途
l 自己调用时用
l 游戏退出的存档、学生选课的信息
2.5.2 dumps
import pickle
dic = {'k1':'v1','k2':'v2','k3':'v3'}
str_dic = pickle.dumps(dic)
print(str_dic) #一串二进制内容
2.5.3 loads
dic2 = pickle.loads(str_dic)
print(dic2) #字典
2.5.4 dump
import time
struct_time = time.localtime(1000000000)
print(struct_time)
f = open('pickle_file','wb')
pickle.dump(struct_time,f)
f.close()
2.5.5 load
f = open('pickle_file','rb')
struct_time2 = pickle.load(f)
print(struct_time2.tm_year)
2.5.6 应用小结
l pickle为人类不可读网络传输
import pickle
class A:
def __init__(self,name,age):
self.name = name
self.age = age
file = open('pickle_file','wb')
alex = A('alex',83)
输出
C:\python3\python3.exe D:/python/untitled2/python_9/lession.py
b'\x80\x03c__main__\nA\nq\x00)\x81q\x01}q\x02(X\x04\x00\x00\x00nameq\x03X\x04\x00\x00\x00alexq\x04X\x03\x00\x00\x00ageq\x05KSub.'
2.5.7 load
import pickle
class A:
def __init__(self,name,age):
self.name = name
self.age = age
输出:
C:\python3\python3.exe D:/python/untitled2/python_9/lession.py
alex 83
2.5.8 dumps
import pickle
class A:
def __init__(self,name,age):
self.name = name
self.age = age
wang = A('alex',83)
pa = pickle.dumps(wang)
pal = pickle.loads(pa)
print(pal.name)
输出
C:\python3\python3.exe D:/python/untitled2/python_9/lession.py
alex
2.5.9 loads
2.5.10 try的用法
用try来尝试里边有多少值
import pickle
file = open('pickle_file','wb')
pickle.dump({1,2,3},file)
pickle.dump({(1,2,3):456},file)
file.close()
file = open('pickle_file','rb')
while True:
try:
print(pickle.load(file))
except EOFError:
break
输出
{1, 2, 3}
{(1, 2, 3): 456}
2.6 shelve
解释:
shelve也是python提供给我们的序列化工具,比pickle用起来更简单一些。
shelve只提供给我们一个open方法,是用key来访问的,使用起来和字典类似
使用方法:
2.6.1 存入
import shelve
f = shelve.open('shelve_file')
f['key'] = {'int':10, 'float':9.5, 'string':'Sample data'} #直接对文件句柄操作,就可以存入数据
f.close()
import shelve
f1 = shelve.open('shelve_file')
existing = f1['key'] #取出数据的时候也只需要直接用key获取即可,但是如果key不存在会报错
f1.close()
print(existing)
2.6.2 只读
解释:
这个模块有个限制,它不支持多个应用同一时间往同一个DB进行写操作。所以当我们知道我们的应用如果只进行读操作,我们可以让shelve通过只读方式打开DB
import shelve
f = shelve.open('shelve_file', flag='r')
existing = f['key']
f.close()
print(existing)
2.6.3 保存
解释:
由于shelve在默认情况下是不会记录待持久化对象的任何修改的,所以我们在shelve.open()时候需要修改默认参数,否则对象的修改不会保存
例:
import shelve
f1 = shelve.open('shelve_file')
print(f1['key'])
f1['key']['new_value'] = 'this was not here before'
f1.close()
f2 = shelve.open('shelve_file', writeback=True)
print(f2['key'])
f2['key']['new_value'] = 'this was not here before'
f2.close()
writeback方式有优点也有缺点。优点是减少了我们出错的概率,并且让对象的持久化对用户更加的透明了;但这种方式并不是所有的情况下都需要,首先,使用writeback以后,shelf在open()的时候会增加额外的内存消耗,并且当DB在close()的时候会将缓存中的每一个对象都写入到DB,这也会带来额外的等待时间。因为shelve没有办法知道缓存中哪些对象修改了,哪些对象没有修改,因此所有的对象都会被写入。
2.7 项目开发规范
表格说明:
目录名称 | 目录内容 | 目录说明 |
bin/ | start.py | 执行目录/启动文件 |
conf/ | config.ini/settings.py/my_los_setting.py | 配置文件目录 |
core/ | core.py | 核心代码 |
db/ | **_json/userinfo | json文件信息文件 |
lib/ | red_ini.py/ | 库文件 |
log/ |
| 日志目录 |
第3章 拾遗
3.1 计算文件大小
import os
lst = [r'D:\python\untitled2\python_9']
total_size = 0
while lst:
base_dir = lst.pop()
ret = os.listdir(base_dir)
print(ret)
for name in ret:
abspath = os.path.join(base_dir,name)
if os.path.isfile(abspath):
total_size += os.path.getsize(abspath)
total_size += os.path.getsize(abspath)
elif os.path.isdir(abspath):
lst.append(abspath)
输出
C:\python3\python3.exe D:/python/untitled2/python_9/lession.py
['examp.ini', 'file', 'lession.py', 'pickle_file', 'test.log', 'test2.log', 'userinfo']