【Python】哈希值

少女dtysky

世界Skill

时刻2014.06.23

哈希值是哈希算法生成了一段二进制值,任意的不同数据都拥有不同哈希值,通过这一点可以做很多事情。
本文将会介绍各种数据类型、以及文件在Python中求取哈希值的方法以及应用举例。


1.求法

1.hash:

Python中的hash函数用于求取一个字符串或者数值的哈希值,由于Python中任何数据类型都可以转换为字符串,所以我们利用这个函数来进行简单的哈希值计算,比如:

hash('test')

如此便可以求得字符串'test'的哈希值,同样,如果是数值的话:

hash(1)

不但如此,我们也可以求取list的哈希值:

hash(str([1,2,3]))

也可以求得字典的,但是由于字典本身无序(集合也是如此),所以需要加一些小的变动:

hash(str(sorted({'1':1})))

先将字典排序,而后转为字符串,最后求得哈希值。
倘若是字典嵌套字典,可以对其中的每一个子字典求哈希值,而后求和:

#Return hash for a dict which may contain a dict as its value
def DHash(Dict):
    dh=0
    for tmp in Dict:
        if isinstance(Dict[tmp],dict):
            dh+=hash(tmp)+hash(str(sorted(Dict[tmp],key=lambda d: d[0])))
        else:
            dh+=hash(tmp)+hash(str(Dict[tmp]))
    return dh

注意:
使用这个函数之前,先看一下help的说明:

Return a hash value for the object. Two objects with the same value have the same hash value. The reverse is not necessarily true, but likely.

也就是说,同样的哈希值并不一定对应同样的对象,但大多是,也就是说使用它的时候需要考虑条件是否不是非常严格。


2.hashlib:

Python有一个原生库hashlib,可以用来求取字符串的md5、sha1等等,与hash函数不同,它是一个不可逆的唯一映射(虽然已经被暴力破解,但在大部分使用情况下我们仍然可以如此认为),至少,比hash函数可靠。

若要使用,只需要先加载hashlib库调用函数即可:

md5obj=hashlib.md5()
f=open('path').read()
md5obj.update(f.encode)
hash=md5obj.hexdigest()

但这里有一些细节问题:

1.大文件:

如果文件过大,则不能直接一次性计算,所得结果会与期望不符,这时候需要将文件进行分段,像这样:

while 1:
    f=self.fs.read(8096)
    if not f:
        break
    else:
        md5obj.update(f.encode)

2.空字符串:

在使用是有时会遇到这样的问题:

返回值为:

'd41d8cd98f00b204e9800998ecf8427e'

这是因为读取结束后忘记了将文件seek回开头,将会返回一个空字符串的md5值,所以我们必须要记得在文件的md5值计算结束后将文件seek回文件头:

f.seek(0)

2.例子

1.判断文件、对象改动:

我们可以用哈希值来判断文件或者像是字典这样的对象是否发生了改动,从而进行下一步的操作:

#Only a file had been changed will process it
for f in FileAll:
    Fs.open(f,'rb')
    if HashFile.get(f)==None:
        FileNow.append(f)
    else:
        if Fs.hash()==HashFile[f]:
            pass
        else:
            FileNow.append(f)
    Fs.close()

这一段实现的是,将现有文件的哈希值和已存的该文件列表上一次的哈希表进行比对,如果哈希值不一样,则表明文件被改动,进行处理,否则忽略。
当文件的数量巨大的话,如此可以节省很多不必要的开支。

如果不是自己的创作,少女是会标识出来的,所以要告诉别人是少女写的哦。