为何已在find_class允许的自定义类仍无法通过受限Unpickler反序列化?
解决pickle restricted_loads无法加载自定义类的问题
你的代码里有两个关键错误导致无法加载__main__.Shape:
- 判断逻辑错误:反序列化自定义类时,
find_class接收到的module是__main__,但你的条件只检查module == "builtins"的情况,直接跳过了自定义类的允许判断。 - 允许类的存储格式错误:你把
__main__.Shape作为完整字符串存在allow_classes里,但find_class是分开拿到module(__main__)和name(Shape)的,没法直接匹配这个完整字符串。
修正方案
- 把
allow_classes改成存储(模块名, 类名)的元组集合,方便匹配分开的module和name参数。 - 修改
find_class的逻辑,先判断是否是允许的自定义类,再判断是否是安全的内置类型。 - 别忘了把
Person也加入允许列表,因为Shape实例里包含Person对象,反序列化时也需要加载它。
修正后的完整代码
import builtins import io import os import pickle safe_builtins = { 'range', 'complex', 'set', 'frozenset', 'slice', } # 改成存储(模块名, 类名)的元组集合 allow_classes = { ('__main__', 'Shape'), ('__main__', 'Person') # 必须加入,因为Shape里包含Person实例 } class RestrictedUnpickler(pickle.Unpickler): def find_class(self, module, name): # 先检查是否是允许的自定义类 if (module, name) in allow_classes: # 从当前模块获取类 return globals()[name] # 再检查是否是安全的内置类型 if module == "builtins" and name in safe_builtins: return getattr(builtins, name) # 其他一律禁止 raise pickle.UnpicklingError(f"global '{module}.{name}' is forbidden") def restricted_loads(s): """Helper function analogous to pickle.loads().""" return RestrictedUnpickler(io.BytesIO(s)).load() class Person: def __init__( self, name: str, age: int, ): self.name = name self.age = age class Shape: def __init__( self, name: str, # 修正原代码错误:参数是字符串,不是Person类型 n: int = 50, ): self.person = Person( name = name, age = 10, # 修正原代码错误:age是int类型,传整数而非字符串 ) self.n = n s = Shape( name = "name1", n = 30, ) filepath = os.path.join(os.getcwd(), "temp.pkl") with open(filepath, 'wb') as outp: pickle.dump(s, outp, -1) with open(filepath, 'rb') as inp: x = restricted_loads(inp.read()) # 测试验证 print(x.person.name) # 输出:name1 print(x.n) # 输出:30
另外还修正了原代码里的两个小问题:
- Shape的
name参数类型注解错误,原代码写的是Person,但实际传的是字符串,改成str。 - Person实例化时
age传了字符串"10",但Person的age是int类型,改成整数10避免类型错误。
内容的提问来源于stack exchange,提问作者Suraj
相关产品推荐
相关产品推荐

