Python 版本差异:Python 2 与 Python 3 中 MD5 加密结果不一致的成因与解决

唐可
唐可
发布时间:2026-10-13| 3人浏览过
原创

本文深入解析 Python 2 与 Python 3 在 MD5 加密结果上产生差异的根本原因。主要问题源于 Python 3 默认使用 UTF-8 编码处理字符串,导致包含非 ASCII 字符(如 chr(163))时生成的字节序列与 Python 2 不同。文章通过代码示例对比了两种版本的行为,并推荐通过显式指定 latin1 编码来保持结果一致性,确保跨版本兼容。

起步

在处理某些包含特殊字符的字符串时,Python 2 和 Python 3 生成的 MD5 加密结果会出现不一致的情况。

# python2.7
pwd = "xxx" + chr(163) + "fj"
checkcode = hashlib.md5(pwd).hexdigest()
print checkcode # ea25a328180680aab82b2ef8c456b4ce

# python3.6
pwd = "xxx" + chr(163) + "fj"
checkcode = hashlib.md5(pwd.encode("utf-8")).hexdigest()
print(checkcode) # b517e074034d1913b706829a1b9d1b67

从代码实现的角度来看,差异主要出现在 python3 中。在 Python 3 环境下,必须对字符串执行 encode 操作,否则程序会抛出异常,报错信息如下:

 checkcode = hashlib.md5(pwd).hexdigest()
TypeError: Unicode-objects must be encoded before hashing

产生该错误的根本原因在于,MD5 加密算法要求输入数据必须是 bytes 类型。而在 Python 3 中,字符串默认采用 utf-8 编码方式。因此,为了解决兼容性问题,我们需要显式地使用 UTF-8 对字符串进行解码处理。

分析

当字符串中不包含 chr(163) 这类特殊字符时,Python 2 和 Python 3 的 MD5 计算结果是一致的。这表明问题的核心在于 chr(163) 这一特定字符的处理机制上:

# python2.7
>>> chr(163)
'\xa3'

# python3.6
>>> chr(163)
'\xa3'

这里需要说明的是,通过 chr 函数获取的结果在两个版本中看似一致。为了进一步探究,我们可以将其转换为 bytes 类型进行观察:

# python2.7
>>> bytes(chr(163))
'\xa3'

# python3.6
>>> chr(163).encode()
b'\xc2\xa3'

在 Python 3 中,当 num<128 时,使用 chr(num).encode('utf-8') 方法得到的是 一个 个字符对应的 ASCII 十六进制表示;而当 num>128 时,使用 chr(num).encode('utf-8') 方法得到的则是 两个 个字节的 ASCII 十六进制表示。这种字节长度的差异直接导致了最终哈希值的不同。

解决 为了实现与 Python 2 结果的一致性,建议改用 latin1 编码进行解码处理:

# python3.6
pwd = "xxx" + chr(163) + "fj"
checkcode = hashlib.md5(pwd.encode("latin1")).hexdigest()
print(checkcode)  # ea25a328180680aab82b2ef8c456b4ce

额外 为什么选择 latin1 编码呢?这个答案其实挺有意思的。

首先查看 help(chr) 的帮助文档,可以了解其具体行为:

chr(...)
  chr(i) -> Unicode character
  Return a Unicode string of one character with ordinal i; 0 <= i <= 0x10ffff.

文档说明该函数返回 Unicode 编码中指定位置的一个字符。Python 3 内部统一使用 Unicode 来表示所有字符,即 str 类型。然而,通过 encode 方法处理后,字符串会被编码成 bytes 类型。

在标准的 ASCII 编码中,每个字符占用一个字节,但仅覆盖 1 到 127 的范围。超过 127 的部分(128-255)属于 Extended ASCII 范畴。Python 3 默认的 ASCII 编解码器不包含这部分字符,因此如果尝试执行 chr(163).encode("ascii"),就会报错:'ascii' codec can't encode character '\xa3' in position 3: ordinal not in range(128)。

因此,我们需要一种包含 128-255 范围内字符且采用固定 1 字节大小的编码方式,例如 ISO 8859-1,即 latin1。当然,其他编码如 cp1252 也包含这些字符,但 latin1 是解决此类兼容性问题的常见选择。

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。