处理ImportError异常遇问题:RIPEMD160多fallback方案失效
问题分析与解决
我写了一段带两级降级逻辑的RIPEMD160哈希实现代码:优先依赖编译有RIPEMD160支持的OpenSSL(OpenSSL 3.0默认不再支持),其次依赖未声明依赖的第三方包,最后用纯Python实现。但测试时发现,当OpenSSL不支持且第三方包未安装时,抛出的ModuleNotFoundError未被ImportError捕获,程序直接报错,这是为什么?
代码示例
import hashlib assert issubclass(ModuleNotFoundError, ImportError) def sha256(public_key: bytes) -> bytes: return bytes(hashlib.sha256(public_key).digest()) def hash_160(public_key: bytes) -> bytes: sha256_hash = sha256(public_key) try: md = hashlib.new("ripemd160") md.update(sha256_hash) return md.digest() except ValueError: from Crypto.Hash import RIPEMD160 md = RIPEMD160.new() md.update(sha256_hash) return md.digest() except ImportError: # from . import ripemd # md = ripemd.new(sha256_hash) # return md.digest() return b"" print(hash_160(b"very test"))
报错信息
Traceback (most recent call last): File "/usr/lib/python3.10/hashlib.py", line 160, in __hash_new return _hashlib.new(name, data, **kwargs) ValueError: [digital envelope routines] unsupported During handling of the above exception, another exception occurred: Traceback (most recent call last): File "/home/pierre/dev/test_package/./package1/tests/module1.py", line 14, in hash_160 md = hashlib.new("ripemd160") File "/usr/lib/python3.10/hashlib.py", line 166, in __hash_new return __get_builtin_constructor(name)(data) File "/usr/lib/python3.10/hashlib.py", line 123, in __get_builtin_constructor raise ValueError('unsupported hash type ' + name) ValueError: unsupported hash type ripemd160 During handling of the above exception, another exception occurred: Traceback (most recent call last): File "/home/pierre/dev/test_package/./package1/tests/module1.py", line 31, in <module> print(hash_160(b"very test")) File "/home/pierre/dev/test_package/./package1/tests/module1.py", line 18, in hash_160 from Crypto.Hash import RIPEMD160 ModuleNotFoundError: No module named 'Crypto'
问题根源
尽管ModuleNotFoundError确实是ImportError的子类,但当前代码的异常捕获逻辑存在层级问题:
- 外层
try块仅负责捕获hashlib.new("ripemd160")抛出的ValueError - 当进入
except ValueError块执行导入语句时,抛出的ModuleNotFoundError属于该内部代码的异常,不在外层try的捕获范围内,因此会直接向外抛出,不会触发后面同级的except ImportError块。
修复方案
需要将第三方包的导入逻辑放到嵌套的try-except块中,才能捕获导入失败的异常:
import hashlib assert issubclass(ModuleNotFoundError, ImportError) def sha256(public_key: bytes) -> bytes: return bytes(hashlib.sha256(public_key).digest()) def hash_160(public_key: bytes) -> bytes: sha256_hash = sha256(public_key) try: md = hashlib.new("ripemd160") md.update(sha256_hash) return md.digest() except ValueError: # 嵌套try块捕获第三方包导入失败的异常 try: from Crypto.Hash import RIPEMD160 md = RIPEMD160.new() md.update(sha256_hash) return md.digest() except ImportError: # 执行纯Python实现 # from . import ripemd # md = ripemd.new(sha256_hash) # return md.digest() return b"" print(hash_160(b"very test"))
另一种方案是提前在模块加载阶段尝试导入第三方包,避免函数内嵌套:
import hashlib # 提前尝试导入第三方包,标记是否可用 try: from Crypto.Hash import RIPEMD160 HAS_CRYPTO = True except ImportError: HAS_CRYPTO = False assert issubclass(ModuleNotFoundError, ImportError) def sha256(public_key: bytes) -> bytes: return bytes(hashlib.sha256(public_key).digest()) def hash_160(public_key: bytes) -> bytes: sha256_hash = sha256(public_key) try: md = hashlib.new("ripemd160") md.update(sha256_hash) return md.digest() except ValueError: if HAS_CRYPTO: md = RIPEMD160.new() md.update(sha256_hash) return md.digest() # 执行纯Python实现 # from . import ripemd # md = ripemd.new(sha256_hash) # return md.digest() return b"" print(hash_160(b"very test"))
内容的提问来源于stack exchange,提问作者PiRK
相关产品推荐
相关产品推荐

