模块的三种类型:
- 内置模块:安装python解释器的时候一起装上的
- 第三方模块:扩展模块:需要自己安装
- 自定义模块:你写的py文件
序列化模块
序列:
- 列表
- 元组
- 字符串 *
- bytes *
什么叫序列化
把一个数据类型转换成字符串,bytes类型的过程就是序列化
为什么要把有个数据类型序列化
把一个数据类型储存到文件中,持久储存
-
把一个数据类型通过网络传输的时候
当然你会说用eval()函数,将字符串对象转化为有效的表达式参与求值运算返回计算结果,但是这样不安全.
stu = {'name':'何青','sex':'male'}
ret = str(stu)
print([ret])
print([eval(ret)]) # 用户输入的、文件读入的、网络传入的
>>>["{'name': '何青', 'sex': 'male'}"]
[{'name': '何青', 'sex': 'male'}]
json模块
json模块的作用是把数据类型序列化储存
- json支持所有语言
- 只支持非常少的数据类型:字典的key必须是字符串,只支持:数字,字符串,列表,字典
import json
lst = [1,2,3,4,'aaa','bbb']
ret = json.dumps(lst) # 序列化的过程
print(lst,type(lst))
print(ret,type(ret))
d = json.loads(ret) # 反序列化的过程
print('d-->',d,type(d))
[1, 2, 3, 4, 'aaa', 'bbb']
[1, 2, 3, 4, "aaa", "bbb"]
d--> [1, 2, 3, 4, 'aaa', 'bbb']
pickle模块
pickle模块只支持python语言,但是支持几乎所有的数据类型,在编程中我们还是经常使用json模块.
import pickle
class Course():
def __init__(self,name,price):
self.name = name
self.price = price
python = Course('python',29800)
ret = pickle.dumps(python)#序列化
print(ret)
>>>b'\x80\x03c__main__\nCourse\nq\x00)\x81q\x01}q\x02(X\x04\x00\x00\x00nameq\x03X\x06\x00\x00\x00pythonq\x04X\x05\x00\x00\x00priceq\x05Mhtub.'
p = pickle.loads(ret)#反序列化
print(p.name,p.price)
>>python 29800
时间模块
表示时间的三种方式
time模块被称为时间模块,在python中,通常用这三种方法来表示时间:
-
时间戳(Timestamp)
时间戳表示的是从1970年1月1日00:00:00开始按秒计算的偏移量.是float类型
import time time.time()#获取当前的时间戳
时间戳是一个经过加密后形成的凭证文档,包括3部分:
- 需加时间戳的文件摘要(digest)
- DTS收到的文件的日期和时间
- DTS的数字签名
过程:将需要时间戳的文件用Hash编码加密成摘要,发到DTS,DTS加入收到文件摘要的日期和时间信息后再对该文件加密,最后发给用户.
书面签署文件的时间是由签署本人自己写的,而数字时间戳是由认证单位的DTS添加的,以DTS收到的文件的时间为依据.
-
时间元组(struct_time)
时间元组一共有9个元素:(年,月,日,时,分,秒,一年中第几周,一年中第几天等)
索引(Index) 属性(Attribute) 值(Values) 0 tm_year(年) 比如2011 1 tm_mon(月) 1 - 12 2 tm_mday(日) 1 - 31 3 tm_hour(时) 0 - 23 4 tm_min(分) 0 - 59 5 tm_sec(秒) 0 - 60 6 tm_wday(weekday) 0 - 6(0表示周一) 7 tm_yday(一年中的第几天) 1 - 366 8 tm_isdst(是否是夏令时) 默认为0 -
时间字符串(Format string)
在python中使用下表格式化符号对时间进行格式化:
%y 两位数的年份表示(00-99) %Y 四位数的年份表示(000-9999) %m 月份(01-12) %d 月内中的一天(0-31) %H 24小时制小时数(0-23) %I 12小时制小时数(01-12) %M 分钟数(00=59) %S 秒(00-61) (2) %a 本地简化星期名称 %A 本地完整星期名称 %b 本地简化的月份名称 %B 本地完整的月份名称 %c 本地相应的日期表示和时间表示 %j 年内的一天(001-366) %p 本地A.M.或P.M.的等价符 (1) %U 一年中的星期数(00-53)星期天为星期的开始 (3) %w 星期(0-6),星期天为星期的开始 (3) %W 一年中的星期数(00-53)星期一为星期的开始 %x 本地相应的日期表示 %X 本地相应的时间表示 %Z 当前时区的名称 %% %号本身
3个数字的含义:
- %p只有与%I配合使用才有效果.
- 文档中的强调确实是0~61,而不是59秒,闰年占两秒
- 当使用striptime()函数时,只有这一年的周数和天数确定时%U和%W才会被计算.
认识几种格式:
#导入时间模块
>>>import time
#时间戳
>>>time.time()
1500875844.800804
#时间字符串
>>>time.strftime("%Y-%m-%d %X")
'2017-07-24 13:54:37'
>>>time.strftime("%Y-%m-%d %H-%M-%S")
'2017-07-24 13-55-04'
#时间元组:localtime将一个时间戳转换为当前时区的struct_time
time.localtime()
time.struct_time(tm_year=2017, tm_mon=7, tm_mday=24,
tm_hour=13, tm_min=59, tm_sec=37,
tm_wday=0, tm_yday=205, tm_isdst=0)
小结:时间戳是计算机能够识别的时间;时间字符串是人能够看懂的时间;元组则是用来操作时间的
几种格式的转换
time模块
在time模块里边还有一些内置函数有做时间处理的,也有做格式转换的:
time函数
time()函数用于返回当前时间的时间戳.
import time
print('当前的时间戳为%f'%time.time())#第一个time是time模块
localtime([secs])函数
localtime()函数的作用是格式化时间戳为本地时间.如果secs参数未输入,就以当前时间为转换标准.secs 为time.struct_time的秒数.
import time
print(time.localtime())
>>>time.struct_time(tm_year=2018, tm_mon=9, tm_mday=4, tm_hour=16, tm_min=23, tm_sec=45, tm_wday=1, tm_yday=247, tm_isdst=0)
gmtime([secs])函数
gmtime()函数用于将一个时间戳转换为UTC时区的struct_time,可选参数secs表示为从1970年1月1日到现在的秒数.gmtime()函数的默认值为time.time(),函数返回time.struct_time类型的对象(struct_time是在time模块中定义的表示时间的对象)
import time
print(time.gmtime())
>>time.struct_time(tm_year=2018, tm_mon=9, tm_mday=4, tm_hour=8, tm_min=32, tm_sec=39, tm_wday=1, tm_yday=247, tm_isdst=0)
看上边的结果作者是在东八区,与零时区差8个小时,gmtime()函数把时区换成了零时区.
mktime(t)函数
mktime()函数用于执行与gmtime()函数和localtime()函数相反的操作,接受struct_time对象作为参数,返回用秒作为时间表示的浮点数.输入的值不是合法时间,就会触发OverflowError或ValueError.
import time
t = (2018,9,4,16,34,56,1,247,0)
print(time.mktime(t))
>>>1536050096.0
asctime([t])函数
asctime()函数用于接受时间元组并返回一个可读的形式的24个字符的字符串.
import time
t =(2018,9,4,16,34,56,1,247,0)
print(time.asctime(t))
>>>Tue Sep 4 16:34:56 2018
ctime([secs])函数
ctime函数用于把时间戳转换为asctime()函数格式的形式.可以指定参数secs,也可以空着,它默认将time.time()做为参数.ctime的作用相当于asctime(localtime(secs))
import time
print(time.ctime())
>>>Tue Sep 4 16:55:00 2018
sleep函数
sleep函数用于推迟调用线程的运行,可通过输入secs时间来指定推迟时间,
import time
print('start:%s'%time.ctime())
time.sleep(20)
print('End:%s'%time.ctime())
>>>start:Tue Sep 4 17:00:47 2018
End:Tue Sep 4 17:01:07 2018
由结果可以知道,输出时间间隔了20秒
clock()函数
clock函数,是用来判断CPU的运行时间的并以浮点数返回,衡量不同程序的运行时间.在Windows系统上第一层返回的是程序的运行时间,第二次调用返回的是第一次调用后到第二次调用的时间间隔.
import time
def procedure():
time.sleep(5)
t1 = time.clock()
procedure()
print(time.clock-t1)
strftime()函数
strftime函数用于接受时间元组,并返回可读字符串表示的当地时间.
import time
print(time.strftime('%Y-%m-%d',time.localtime()))
>>>2018-09-04
strptime()函数
strptime()函数用于根据指定格式把一个时间字符串解析为一个时间元组.
import time
print(time.strptime('4 Sep 17','%d%b%y'))
>>>time.struct_time(tm_year=2017, tm_mon=9, tm_mday=4, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=0, tm_yday=247, tm_isdst=-1)
随机函数模块
取随机小数:
random()可以去随机小数,默认大于0且小于1的数,
import random
random.random()
也可以指定区间
import random
random,uniform(2,4)#大于2小于4的小数
取随机整数:
>>> random.randint(1,5) # 大于等于1且小于等于5之间的整数
>>> random.randrange(1,10,2) # 大于等于1且小于10之间的奇数
随机选择返回:
#随机选择一个返回
>>> random.choice([1,'23',[4,5]]) # #1或者23或者[4,5]
#随机选择多个返回,返回的个数为函数的第二个参数
>>> random.sample([1,'23',[4,5]],2) # #列表元素任意2个组合
[[4, 5], '23']
打乱列表顺序
>>> item=[1,3,5,7,9]
>>> random.shuffle(item) # 打乱次序
>>> item
[5, 1, 3, 7, 9]
>>> random.shuffle(item)
>>> item
[5, 9, 7, 1, 3]
随机生成验证码
#请你生成一个6位数的验证码
#字母怎么生成 chr()把数字转变成字母
st = random.randint(65,90)
print(chr(st))
num = random.randint(97,122)
print(chr(num))
#每一位上出现的内容可以是数字,也可以是字母
def get_code(n=6,alph_flag=True):
code=''
for i in range(n):
c = str(random.randint(0,9))
if alph_flag:
alpha_upper=chr(random.randint(65, 90))
alpha_lower=chr(random.randint(97, 122))
c = random.choice([c,alpha_upper,alpha_lower])
code +=c
return code
ret = get_code(6)
print(ret)
OS模块
# os 和操作系统交互
# 文件和文件夹的操作
# os.remove
# os.rename
# os.mkdir
# os.makedirs
# os.rmdir
# os.removedirs
# os.listdir
# os.stat 获取文件的信息
# 路径的操作
# os.path.join 目录的拼接
# os.path.split(path) # 将路径分割成两个部分,目录、文件/文件夹的名字
# os.path.dirname(path) # 返回这个path的上一级目录
# os.path.basename(path) # 文件/文件夹的名字
# os.path.exits 这个路径是否存在
# os.path.isfile 是否文件目录
# os.path.isdir 是否文件夹目录
# os.path.abspath 规范文件目录、返回一个绝对路径
# os.path.getsize
# 和python程序的工作目录相关的
# getcwd # 获取当前的工作目录 get current working dir
# chdir # 改变当前的工作目录 change dir
# 执行操作系统命令
# os.system(命令)
# os.popen(命令).read()
# __file__文件中的一个内置变量,描述的是这个文件的绝对路径
os路径处理
#方式一:推荐使用
import os
#具体应用
import os,sys
possible_topdir = os.path.normpath(os.path.join(
os.path.abspath(__file__),
os.pardir, #上一级
os.pardir,
os.pardir
))
sys.path.insert(0,possible_topdir)
#方式二:不推荐使用
os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
sys模块
# sys 和python解释器
# sys.argv 执行py文件的时候传入的参数
# sys.path 查看模块搜索路径 import 模块的时候从这个路径下来寻找
# sys.modules 查看当前导入的模块和它的命名空间
collections模块
根据基础数据类型又做了一些扩展,例如:counter,deque,defaultdict,
namedtuple,orderedDict.
1.namedtuple: 生成可以使用名字来访问元素内容的tuple
2.deque: 双端队列,可以快速的从另外一侧追加和推出对像
3.Counter: 计数器,主要用来计数
4.OrderedDict: 有序字典
5.defaultdict: 带有默认值的字典
namedtuple
生成可以使用名字来访问元素内容的tuple,
例如:
p =(1,2)
单看这个元组,很难用来表示一个坐标,但是用了namedtiple定义就不一样了.
from collections import namedtuple:
Point = namedtuple('Point',['x','y'])
p = Point(1,2)
pringt(p.x)
print(p.y)
>>>1
>>>2
from collections import namedtuple
birth = namedtuple('Struct_time',['year','month','day'])
b1 = birth(2018,9,5)
print(type(b1))
print(b1.year)
print(b1.month)
print(b1.day)
print(b1)
# ['year','month','day']是对象属性名
# Struct_time是类 的名字
# 这个类最大的特点就是一旦实例化 不能修改属性的值
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)])
>>> od = OrderedDict()
>>> od['z'] = 1
>>> od['y'] = 2
>>> od['x'] = 3
>>> od.keys() # 按照插入的Key的顺序返回
['z', 'y', 'x']
注意,OrderedDict
的Key会按照插入的顺序排列,不是Key本身排序:
defaultdict
有如下值集合 [11
,22
,33
,44
,55
,66
,77
,88
,99
,90.
..],将所有大于 66` `的值保存至字典的第一个key中,将小于
66的值保存至第二个key的值中。
即: {'k1'
: 大于66` `,
'k2': 小于
66``}
values = [11, 22, 33,44,55,66,77,88,99,90]
my_dict = {}
for value in values:
if value>66:
if my_dict.has_key('k1'):
my_dict['k1'].append(value)
else:
my_dict['k1'] = [value]
else:
if my_dict.has_key('k2'):
my_dict['k2'].append(value)
else:
my_dict['k2'] = [value]
原生字典解决方法
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)
defaultdict字典解决方法
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})
hanslib * * ***
hanslib是一种内部不只有一种算法的模块.但是由于数据不安全性,为了保证用户信息的绝对安全,所以所有人的密码都不能以明文的形式储存,而应该经过适当的处理以密文的形式存起来.
hanslib被称为摘要算法,它通过一个函数把任意长度的摘要digest,目的是为了发现原始数据是否被人篡改过.(用16进制的字节表达)
hanslib函数是一个单向函数,计算容易,反推难,常见的方法有MD5(32位)SHA(40)位.
import hashlib
md5 = hashlib.md5()
md5.update('how to use md5 in python hashlib?')
print md5.hexdigest()
计算结果如下:
d26a53750bc40b38b65a520292f69306
md5_obj = hashlib.md5()
md5_obj.update(b'alex3714')
md5_obj.update('999'.encode('utf-8'))
ret = md5_obj.hexdigest()
print(ret,type(ret),len(ret))
#数据量大的话可以分开update()然后再统一输出.
登录验证:
import hashlib
usrname = input('username : ')
passwd = input('password : ')
with open('userinfo') as f:
for line in f:
usr,pwd = line.strip().split('|')
if usrname == usr and get_md5(passwd) == pwd:
print('登录成功')
break
else:
print('登录失败')
多种算法
md5算法 :32位16进制的数字字符组成的字符串
应用最广大的摘要算法
效率高,相对不复杂,如果只是传统摘要不安全
sha算法 :40位的16进制的数字字符组成的字符串
sha算法要比md5算法更复杂
且shan n的数字越大算法越复杂,耗时越久,结果越长,越安全
加盐,动态加盐
为了保证摘要算法的安全性,我们可以采用加盐的范式来对数据进行隐藏.
加盐
def get_md5(s):
md5_obj = hashlib.md5('盐'.encode('utf-8'))
md5_obj.update(s.encode('utf-8'))
ret = md5_obj.hexdigest()
return ret
但是这种方法也不好,如果被人知道了盐是什么的话依然你能破解出密码.所以我们采用动态加盐的方式.
动态加盐
每一个用户创建一个盐 - 用户名
def get_md5(user,s):
md5_obj = hashlib.md5(user.encode('utf-8'))
md5_obj.update(s.encode('utf-8'))
ret = md5_obj.hexdigest()
return ret
文件 的一致性
我们在下载文件的时候如何判断下载的文件就是原文件,那么,我们可以采用摘要函数来对其进行判断.
# 下载的是视频、或者大文件
# 应该是以rb的形式来读 读出来的都是bytes
# 并且不能按行读 也不能一次性读出来
# getsize() --> 字节大小
# 10240
# 1024
# D:\讲师课程文件\python讲师 Jingliyang\day24\video\3.习题讲解2.mp4
import os
import hashlib
def get_file_md5(file_path,buffer = 1024):
md5_obj = hashlib.md5()
# file_path = r'3.习题讲解2.mp4' # 路径里不能有空格
file_size = os.path.getsize(file_path)
with open(file_path,'rb') as f:
while file_size:
content = f.read(buffer) # 1024 1024 1024 。。。 5
file_size -= len(content) # 5 -=5
md5_obj.update(content)
return md5_obj.hexdigest()
configparser *
该模块适用于配置文件,当你需要把你的userinfo文件copy到其他目录或者电脑下,不在当前这个userinfo文件所在的目录去执行py文件的时候,需要把路径记录在这里
import configparser
config = configparser.ConfigParser()
config["DEFAULT"] = {'ServerAliveInterval': '45',
'Compression': 'yes',
'CompressionLevel': '9',
'ForwardX11':'yes'
}
config['bitbucket.org'] = {'User':'hg'}
config['topsecret.server.com'] = {'Host Port':'50022','ForwardX11':'no'}
with open('example.ini', 'w') as configfile:
config.write(configfile)
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']) #
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
logging** * **
默认情况下Python的logging模块将日志打印到了标准输出中,且只显示了大于等于WARNING级别的日志,这说明默认的日志级别设置为WARNING(日志级别等级CRITICAL > ERROR > WARNING > INFO > DEBUG),默认的日志格式为日志级别:Logger名称:用户输出消息。
import logging
logging.debug('debug message')
logging.info('info message')
logging.warning('warning message')
logging.error('error message')
logging.critical('critical message')
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')
# 对象的配置
# 解决中文问题
# 同时向文件和屏幕输出内容
# 先创建一个log对象 logger
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)
# 还要创建一个控制文件输出的文件操作符
fh = logging.FileHandler('mylog.log')
# 还要创建一个控制屏幕输出的屏幕操作符
sh = logging.StreamHandler()
# 要创建一个格式
fmt = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
fmt2 = logging.Formatter('%(asctime)s - %(name)s[line:%(lineno)d] - %(levelname)s - %(message)s')
# 文件操作符 绑定一个 格式
fh.setFormatter(fmt)
# 屏幕操作符 绑定一个 格式
sh.setFormatter(fmt2)
sh.setLevel(logging.WARNING)
# logger对象来绑定:文件操作符, 屏幕操作符
logger.addHandler(sh)
logger.addHandler(fh)
logger.debug('debug message') # 计算或者工作的细节
logger.info('info message') # 记录一些用户的增删改查的操作
logger.warning('input a string type') # 警告操作
logger.error('error message') # 错误操作
logger.critical('critical message') # 批判的 直接导致程序出错退出的