Python模块一java
阅读目录node
序列化 random 模块 os模块 sys模块 hashlib模块 collections模块
回到顶部
序列化python
咱们今天学习下序列化,什么是序列化呢? 将本来的字典、列表等内容转换成一个字符串的过程就叫作序列化。算法
为何要有序列化模块: 好比,咱们在python代码中计算的一个数据须要给另一段程序使用,那咱们怎么给? 如今咱们能想到的方法就是存在文件里,而后另外一个python程序再从文件里读出来。 可是咱们都知道,对于文件来讲是没有字典这个概念的,因此咱们只能将数据转换成字典放到文件中。 你必定会问,将字典转换成一个字符串很简单,就是str(dic)就能够办到了,为何咱们还要学习序列化模块呢? 没错序列化的过程就是从dic 变成str(dic)的过程。如今你能够经过str(dic),将一个名为dic的字典转换成一个字符串, 可是你要怎么把一个字符串转换成字典呢? 聪明的你确定想到了eval(),若是咱们将一个字符串类型的字典str_dic传给eval,就会获得一个返回的字典类型了。 eval()函数十分强大,可是eval是作什么的?e官方demo解释为:将字符串str当成有效的表达式来求值并返回计算结果。 BUT!强大的函数有代价。安全性是其最大的缺点。 想象一下,若是咱们从文件中读出的不是一个数据结构,而是一句"删除文件"相似的破坏性语句,那么后果实在不堪设设想。 而使用eval就要担这个风险。 因此,咱们并不推荐用eval方法来进行反序列化操做(将str转换成python中的数据结构)shell
序列化的目的数据库
一、以某种存储形式使自定义对象持久化;
二、将对象从一个地方传递到另外一个地方。
三、使程序更具维护性。json
json安全
Json模块提供了四个功能:dumps、dump、loads、loadbash
dumps 及 loads数据结构
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"}
dic2 = json.loads(str_dic) #反序列化:将一个字符串格式的字典转换成一个字典
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'}]
dump 及 load
import json
f = open('json_file','w')
dic = {'k1':'v1','k2':'v2','k3':'v3'}
json.dump(dic,f) #dump方法接收一个文件句柄,直接将字典转换成json字符串写入文件
f.close()
f = open('json_file')
dic2 = json.load(f) #load方法接收一个文件句柄,直接将文件中的json字符串转换成数据结构返回
f.close()
print(type(dic2),dic2)
其余参数说明
参数说明
json格式化输出
import json
data = {'username':['李华','二愣子'],'sex':'male','age':16}
json_dic2 = json.dumps(data,sort_keys=True,indent=2,separators=(',',':'),ensure_ascii=False)
print(json_dic2)
pickle模块
用于序列化的两个模块
json,用于字符串 和 python数据类型间进行转换 pickle,用于python特有的类型 和 python的数据类型间进行转换 pickle模块提供了四个功能:dumps、dump(序列化,存)、loads(反序列化,读)、load (不只能够序列化字典,列表...能够把python中任意的数据类型序列化)pickle是python特有的模块.
import pickle
dic = {'k1':'v1','k2':'v2','k3':'v3'}
str_dic = pickle.dumps(dic)
print(str_dic) #一串二进制内容
dic2 = pickle.loads(str_dic)
print(dic2) #字典
import time
struct_time = time.localtime(1000000000)
print(struct_time)
f = open('pickle_file','wb')
pickle.dump(struct_time,f)
f.close()
f = open('pickle_file','rb')
struct_time2 = pickle.load(f)
print(struct_time2.tm_year)
这时候机智的你又要说了,既然pickle如此强大,为何还要学json呢? 这里咱们要说明一下,json是一种全部的语言均可以识别的数据结构。 若是咱们将一个字典或者序列化成了一个json存在文件里,那么java代码或者js代码也能够拿来用。 可是若是咱们用pickle进行序列化,其余语言就不能读懂这是什么了~ 因此,若是你序列化的内容是列表或者字典,咱们很是推荐你使用json模块 但若是出于某种缘由你不得不序列化其余的数据类型,而将来你还会用python对这个数据进行反序列化的话,那么就可使用pickle
总结:
json模块里的dumps是将python的数据结构转换成字符串,loads是将字符串类型转换成python的数据结构
json模块里的dump是将python的数据结构转换成字符串,而后存入到文件当中
json模块里的load是将文件中字符串类型转换成python的数据结构
pickle模块里的dumps是将python的数据结构转换成二进制的文件,loads是将二进制的文件转换成python的
数据结构
pickle模块里的dump是将python的数据结构转换成二进制而后存入到文件中
pickle模块里的load是将文件中的二进制文件转成python的数据结构
回到顶部
random 模块
random是一个随机数模块,咱们通常用来生成一些没有规则的内容
获取0-1之间的随机小数
import random
print(random.random())
咱们能够获取0到1之间的随机的小数,可是还可以知足你,你想要生成指定的数字内的随机小数怎么办??
import random
print(random.uniform(1,5))
这样写完后,你就有又想法了,说小数你实现了.整数怎么作到随机呢?老铁别急
import random
print(random.randint(1,5))
你这样是实现了,我想让你给生成随机的奇数和偶数,怎么样不会了吧??
import random
print(random.randrange(1,5,2)) #随机生成1-5的奇数
print(random.randrange(0,5,2)) #随机生成0-5的偶数
我还真发现了,真有点难不住你了,我如今有一个列表 lst = ['张开','宝元','佩奇','太白'],你给我随机抽一我的出来
import random
lst = ['张开','宝元','佩奇','太白']
print(random.choice(lst))
看来仍是有两把刷子的,我在考考你.怎么给我随机抽出两个来
import random
lst = ['张开','宝元','佩奇','太白']
print(random.choices(lst,k=2))
差点就被你骗你了,要不是我眼疾手快,发现了你随机出来的两个内容是有重复的,我还就要夸你了,没有知足需求从新实现
import random
lst = ['张开','宝元','佩奇','太白']
print(random.sample(lst,k=2))
能够啊,真是少年有为啊,难不住了,看来事要逼着我使用绝招了.我给你一个列表你给我让他变成随机排序的
import random
lst = [1,2,3,4,5,6]
random.shuffle(lst)
print(lst)
看来仍是真是不简单啊.老衲服了!
回到顶部
os模块
os模块是与操做系统交互的一个接口
#和文件夹相关
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下为"\r\n",Linux下为"\n"
os.pathsep 输出用于分割文件路径的字符串 win下为;,Linux下为:
os.name 输出字符串指示当前使用平台。win->'nt'; Linux->'posix'
os.system("bash command") 运行shell命令,直接显示
os.popen("bash command).read() 运行shell命令,获取执行结果
os.environ 获取系统环境变量
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的大小
os.getcwd() 获取当前工做目录,即当前python脚本工做的目录路径
os.chdir("dirname") 改变当前脚本工做目录;至关于shell下cd
os.curdir 返回当前目录: ('.')
os.pardir 获取当前目录的父目录字符串名:('..')
注意:os.stat('path/filename') 获取文件/目录信息 的结构说明
stat 结构:
st_mode: inode 保护模式
st_ino: inode 节点号。
st_dev: inode 驻留的设备。
st_nlink: inode 的连接数。
st_uid: 全部者的用户ID。
st_gid: 全部者的组ID。
st_size: 普通文件以字节为单位的大小;包含等待某些特殊文件的数据。
st_atime: 上次访问的时间。
st_mtime: 最后一次修改的时间。
st_ctime: 由操做系统报告的"ctime"。在某些系统上(如Unix)是最新的元数据更改的时间,在其它系统上(如Windows)是建立时间(详细信息参见平台的文档)。
回到顶部
sys模块
sys模块是与python解释器交互的一个接口
sys.argv 命令行参数List,第一个元素是程序自己路径
sys.exit(n) 退出程序,正常退出时exit(0),错误退出sys.exit(1)
sys.version 获取Python解释程序的版本信息
sys.path 返回模块的搜索路径,初始化时使用PYTHONPATH环境变量的值
sys.platform 返回操做系统平台名称
回到顶部
hashlib模块
算法介绍 Python的hashlib提供了常见的摘要算法,如MD5,SHA1等等。
什么是摘要算法呢?摘要算法又称哈希算法、散列算法。它经过一个函数,把任意长度的数据转换为一个长度固定的数据串(一般用16进制的字符串表示)。
摘要算法就是经过摘要函数f()对任意长度的数据data计算出固定长度的摘要digest,目的是为了发现原始数据是否被人篡改过。
摘要算法之因此能指出数据是否被篡改过,就是由于摘要函数是一个单向函数,计算f(data)很容易,但经过digest反推data却很是困难。并且,对原始数据作一个bit的修改,都会致使计算出的摘要彻底不一样。
咱们以常见的摘要算法MD5为例,计算出一个字符串的MD5值:
import hashlib
md5 = hashlib.md5()
md5.update('how'.encode('utf-8'))
print(md5.hexdigest())
结果:db88a0257c220dbfdd2e40f6152d6a8d
若是数据量很大,能够分块屡次调用update(),最后计算的结果是同样的:
import hashlib
md5 = hashlib.md5()
md5.update('how你好啊,我很差'.encode('utf-8'))
print(md5.hexdigest())
结果:3bfa4bfb7b59a59f27c24ebdd89cd13c
import hashlib
md5 = hashlib.md5()
md5.update('how'.encode('utf-8'))
md5.update('你好啊,我很差'.encode('utf-8'))
print(md5.hexdigest())
结果:3bfa4bfb7b59a59f27c24ebdd89cd13c
MD5是最多见的摘要算法,速度很快,生成结果是固定的128 bit字节,一般用一个32位的16进制字符串表示。另外一种常见的摘要算法是SHA1,调用SHA1和调用MD5彻底相似:
import hashlib
sha1 = hashlib.sha1()
sha1.update('how to use sha1 in'.encode('utf-8'))
sha1.update('python hashlib?'.encode('utf-8'))
print(sha1.hexdigest())
结果:86e1eae2a08c152d39b55baed085c71a0cc9d10b
SHA1的结果是160 bit字节,一般用一个40位的16进制字符串表示。
SHA1的安全系数比MD5还要高一些,并且摘要的长度要比MD5长一些.
比SHA1更安全的算法是SHA256和SHA512,不过越安全的算法越慢,并且摘要长度更长。
摘要算法应用 任何容许用户登陆的网站都会存储用户登陆的用户名和口令。如何存储用户名和口令呢?方法是存到数据库表中:
name | password |
---|---|
michael | 123456 |
bob | abc999 |
alice | alice2008 |
若是以明文保存用户口令,数据库泄露,全部用户的口令就落入黑客的手里就......
此外,网站运维人员是能够访问数据库的,也就是能获取到全部用户的口令。正确的保存口令的方式是不存储用户的明文口令,而是存储用户口令的摘要,好比MD5:
username | password |
---|---|
michael | e10adc3949ba59abbe56e057f20f883e |
bob | 878ef96e86145580c38c87f0410ad153 |
alice | 99b1c2188db85afee403b1536010c2c9 |
考虑这么个状况,不少用户喜欢用123456,888888,password这些简单的口令,因而,黑客能够事先计算出这些经常使用口令的MD5值,获得一个反推表:
'e10adc3949ba59abbe56e057f20f883e': '123456'
'21218cca77804d2ba1922c33e0151105': '888888'
'5f4dcc3b5aa765d61d8327deb882cf99': 'password'
这样,无需破解,只须要对比数据库的MD5,黑客就得到了使用经常使用口令的用户帐号。
对于用户来说,固然不要使用过于简单的口令。可是,咱们可否在程序设计上对简单口令增强保护呢?
因为经常使用口令的MD5值很容易被计算出来,因此,要确保存储的用户口令不是那些已经被计算出来的经常使用口令的MD5,这一方法经过对原始口令加一个复杂字符串来实现,俗称“加盐”:
import hashlib
md5 = hashlib.md5('salt'.encode('utf-8')) #这是加盐了的
md5.update('how你好啊,我很差'.encode('utf-8'))
print(md5.hexdigest())
import hashlib
md5 = hashlib.md5()
md5.update('how你好啊,我很差'.encode('utf-8'))
print(md5.hexdigest())
通过Salt处理的MD5口令,只要Salt不被黑客知道,即便用户输入简单口令,也很难经过MD5反推明文口令。
可是若是有两个用户都使用了相同的简单口令好比123456,在数据库中,将存储两条相同的MD5值,这说明这两个用户的口令是同样的。有没有办法让使用相同口令的用户存储不一样的MD5呢?
若是假定用户没法修改登陆名,就能够经过把登陆名做为Salt的一部分来计算MD5,从而实现相同口令的用户也存储不一样的MD5。
摘要算法在不少地方都有普遍的应用。要注意摘要算法不是加密算法,不能用于加密(由于没法经过摘要反推明文),只能用于防篡改,可是它的单向计算特性决定了能够在不存储明文口令的状况下验证用户口令。
回到顶部
collections模块
在内置数据类型(dict、list、set、tuple)的基础上,collections模块还提供了几个额外的数据类型:Counter、deque、defaultdict、namedtuple和OrderedDict等。
1.namedtuple: 生成可使用名字来访问元素内容的tuple
2.deque: 双端队列,能够快速的从另一侧追加和推出对象
3.Counter: 计数器,主要用来计数
4.OrderedDict: 有序字典
5.defaultdict: 带有默认值的字典
namedtuple
咱们知道tuple能够表示不变集合,例如,一个点的二维坐标就能够表示成:
p = (1, 2)
可是,看到(1, 2),很难看出这个tuple是用来表示一个坐标的。
这时,namedtuple就派上了用场:
from collections import namedtuple
Point = namedtuple('Point', ['x', 'y'])
p = Point(1, 2)
p.x
1
p.y
2
相似的,若是要用坐标和半径表示一个圆,也能够用namedtuple定义:
namedtuple('名称', [属性list]):
Circle = namedtuple('Circle', ['x', 'y', 'r'])
deque
使用list存储数据时,按索引访问元素很快,可是插入和删除元素就很慢了,由于list是线性存储,数据量大的时候,插入和删除效率很低。
deque是为了高效实现插入和删除操做的双向列表,适合用于队列和栈:
from collections import deque
q = deque(['a', 'b', 'c'])
q.append('x')
q.appendleft('y')
q
deque(['y', 'a', 'b', 'c', 'x'])
deque除了实现list的append()和pop()外,还支持appendleft()和popleft(),这样就能够很是高效地往头部添加或删除元素。
OrderedDict
使用dict时,Key是无序的。在对dict作迭代时,咱们没法肯定Key的顺序。
若是要保持Key的顺序,能够用OrderedDict:
from collections import OrderedDict
d = dict([('a', 1), ('b', 2), ('c', 3)])
d # dict的Key是无序的
{'a': 1, 'c': 3, 'b': 2}
od = OrderedDict([('a', 1), ('b', 2), ('c', 3)])
od # OrderedDict的Key是有序的
OrderedDict([('a', 1), ('b', 2), ('c', 3)])
注意,OrderedDict的Key会按照插入的顺序排列,不是Key自己排序:
defaultdict
有以下值集合 [11,22,33,44,55,66,77,88,99,90...],将全部大于 66 的值保存至字典的第一个key中,将小于 66 的值保存至第二个key的值中。
即: {'k1': 大于66 , 'k2': 小于66}
li = [11,22,33,44,55,77,88,99,90]
result = {}
for row in li:
if row > 66:
if 'key1' not in result:
result['key1'] = []
result['key1'].append(row)
else:
if 'key2' not in result:
result['key2'] = []
result['key2'].append(row)
print(result)
from collections import defaultdict
values = [11, 22, 33,44,55,66,77,88,99,90]
my_dict = defaultdict(list)
for value in values:
if value>66:
my_dict['k1'].append(value)
else:
my_dict['k2'].append(value)
使用dict时,若是引用的Key不存在,就会抛出KeyError。若是但愿key不存在时,返回一个默认值,就能够用defaultdict:
from collections import defaultdict
dd = defaultdict(lambda: 'N/A')
dd['key1'] = 'abc'
dd['key1'] # key1存在
'abc'
dd['key2'] # key2不存在,返回默认值
'N/A'
Counter
Counter类的目的是用来跟踪值出现的次数。它是一个无序的容器类型,以字典的键值对形式存储,其中元素做为key,其计数做为value。计数值能够是任意的Interger(包括0和负数)。Counter类和其余语言的bags或multisets很类似。
c = Counter('abcdeabcdabcaba') print c 输出:Counter({'a': 5, 'b': 4, 'c': 3, 'd': 2, 'e': 1})