Python学习之旅(二十七)
python基础知识(26):常用内建模块(ⅱ)
1、hashlib
python的hashlib提供了常见的摘要算法,如md5,sha1等
摘要算法又称哈希算法、散列算法。
(1)它通过一个函数,把任意长度的数据转换为一个长度固定的数据串(通常用16进制的字符串表示)
(2)摘要算法就是通过摘要函数f()
对任意长度的数据data
计算出固定长度的摘要digest
,目的是为了发现原始数据是否被人篡改过
md5
md5是最常见的摘要算法,速度很快,生成结果是固定的128 bit字节,通常用一个32位的16进制字符串表示
import hashlib md5 = hashlib.md5() md5.update('how to use md5 in python hashlib'.encode('utf-8')) print(md5.hexdigest()) 结果: 8b6e4d30c576051f3ca4be97e8314d15
sha1
import hashlib sha1 = hashlib.sha1() sha1.update('how to use sha1 in python hashlib'.encode('utf-8')) print(sha1.hexdigest()) 结果: 8a4dbc942c7ff059115b56645ab484c4188bd5ce
sha1的结果是160 bit字节,通常用一个40位的16进制字符串表示
比sha1更安全的算法是sha256和sha512,不过越安全的算法不仅越慢,而且摘要长度更长
摘要算法的应用
用户登录网站的用户名和口令都存储数据库,口令使用摘要算法进行加密
当用户登录时,首先计算用户输入的明文口令的md5,然后和数据库存储的md5对比,如果一致,说明口令输入正确,如果不一致,口令肯定错误
要确保存储的用户口令不是那些已经被计算出来的常用口令的md5,这一方法通过对原始口令加一个复杂字符串来实现,俗称“加盐
经过salt处理的md5口令,只要salt不被黑客知道,即使用户输入简单口令,也很难通过md5反推明文口令
设计一个验证用户登录的函数,根据用户输入的口令是否正确
import hashlib db = { 'michael': 'e10adc3949ba59abbe56e057f20f883e', 'bob': '878ef96e86145580c38c87f0410ad153', 'alice': '99b1c2188db85afee403b1536010c2c9' } def calc_md5(password): md5 = hashlib.md5() md5.update(password.encode('utf-8')) return md5.hexdigest() def login(user, password): md5 = calc_md5(password) if user in db and md5 in db.get(user): print('welcome') else: print('incorrect username or password') login('michael', '123456') login('bob', 'abc999') login('alice', 'alice2008') login('michael', '1234567') login('bob', '123456') login('alice', 'alice2008') 结果: welcome welcome welcome incorrect username or password incorrect username or password incorrect username or password
hmac是密钥相关的哈希运算消息认证码,hmac运算利用哈希算法,以一个密钥和一个消息为输入,生成一个消息摘要作为输出
python自带的hmac模块实现了标准的hmac算法,它利用一个key对message计算“杂凑”后的hash,使用hmac算法比标准hash算法更安全,因为针对相同的message,不同的key会产生不同的hash
import hmac message = b'hello,world!' key = b'secret' h = hmac.new(key, message, digestmod='md5') print(h.hexdigest()) 结果: 21db988f124ebc9fade5492afb9df52d
3、itertools
python的内建模块itertools
提供了非常有用的用于操作迭代对象的函数
(1)count
count()
会创建一个无限的迭代器,所以上述代码会打印出自然数序列,根本停不下来,只能按ctrl+c
退出
import itertools natuals = itertools.count(1) for i in natuals: print(i)
(2)cycle
cycle()
会把传入的一个序列无限重复下去
import itertools cs = itertools.cycle('abc') for i in cs: print(i)
(3)repeat
repeat()
负责把一个元素无限重复下去,不过如果提供第二个参数就可以限定重复次数
import itertools ns = itertools.repeat('a', 3) for i in ns: print(i) 结果: a a a
(4)takewhile
无限序列只有在for
迭代时才会无限地迭代下去,如果只是创建了一个迭代对象,它不会事先把无限个元素生成出来,事实上也不可能在内存中创建无限多个元素
无限序列虽然可以无限迭代下去,但是通常我们会通过takewhile()
等函数根据条件判断来截取出一个有限的序列
import itertools natuals = itertools.count(1) ns = itertools.takewhile(lambda x:x<=10, natuals) for i in ns: print(i) 结果: 1 ... 10
(5)chain
chain()
可以把一组迭代对象串联起来,形成一个更大的迭代器
import itertools for c in itertools.chain('abc','123'): print(c) 结果: a b c 1 2 3
(6)groupby
groupby()
把迭代器中相邻的重复元素挑出来放在一起
实际上挑选规则是通过函数完成的,只要作用于函数的两个元素返回的值相等,这两个元素就被认为是在一组的,而函数返回值作为组的key
如果我们要忽略大小写分组,就可以让元素'a'
和'a'
都返回相同的key
import itertools for key,group in itertools.groupby('monent'): print(key,list(group)) for key,group in itertools.groupby('aaaaabbbbbccc', lambda c:c.upper()): print(key,list(group)) 结果: m ['m'] o ['o'] n ['n'] e ['e'] n ['n'] t ['t'] a ['a', 'a', 'a', 'a', 'a'] b ['b', 'b', 'b', 'b', 'b'] c ['c', 'c', 'c']
4、contextlib
在python中,读写文件这样的资源要特别注意,必须在使用完毕后正确关闭它们。正确关闭文件资源的一个方法是使用try...finally
写try...finally
非常繁琐,使用python的with
语句更加方便
#try..finally... try: f = open('/path/to/file', 'r') f.read() finally: if f: f.close() #with with open('/path/to/file', 'r') as f: f.read()
实现上下文管理是通过__enter__
和__exit__
这两个方法实现的,任何对象只要正确实现了上下文管理,就可以用于with
语句
@contextmanager
编写__enter__
和__exit__
仍然很繁琐,因此python的标准库contextlib
提供了更简单的写法
@closing
如果一个对象没有实现上下文,我们就不能把它用于with
语句。这个时候,可以用closing()
来把该对象变为上下文对象