首先但并非最不重要的是:针对 pickle 的警告主要是如果您可以让第三部分在您的工作流上注入 pickle 数据。如果您确定自己的系统正在创建所有要使用的腌制数据,则根本不存在安全问题。至于兼容性,如果您的 Pickle 文件的生产者和消费者使用相同的 Python 版本,那么它相对容易处理,并且是自动的。
也就是说,对于 JSON,您必须创建一个子类蟒蛇的json.JSONEncoder and json.JSONDecoder https://docs.python.org/3/library/json.html#encoders-and-decoders- 每一个都需要作为cls
论据你所有的json.dump(s)
and json.load(s)
calls.
一个建议是,default
编码器上的方法对类进行编码__module__
, its __name__
和一个标识符键,比如说__custom__
确保它应该被自定义解码,作为字典的键,并且对象的数据作为“数据”键。
在编码器上,您检查__custom__
键,然后他们使用__new__
方法,并填充其字典。就像pickle一样,在类上触发的副作用__init__
不会运行。
您稍后可以增强解码器和编码器,例如,它们在类中搜索__json_encode__
只能处理所需属性的方法。
示例实现:
import json
class GenericJSONEncoder(json.JSONEncoder):
def default(self, obj):
try:
return super().default(obj)
except TypeError:
pass
cls = type(obj)
result = {
'__custom__': True,
'__module__': cls.__module__,
'__name__': cls.__name__,
'data': obj.__dict__ if not hasattr(cls, '__json_encode__') else obj.__json_encode__
}
return result
class GenericJSONDecoder(json.JSONDecoder):
def decode(self, str):
result = super().decode(str)
if not isinstance(result, dict) or not result.get('__custom__', False):
return result
import sys
module = result['__module__']
if not module in sys.modules:
__import__(module)
cls = getattr(sys.modules[module], result['__name__'])
if hasattr(cls, '__json_decode__'):
return cls.__json_decode__(result['data'])
instance = cls.__new__(cls)
instance.__dict__.update(result['data'])
return instance
控制台交互测试:
In [36]: class A:
...: def __init__(self, a):
...: self.a = a
...:
In [37]: a = A('test')
In [38]: b = json.loads(json.dumps(a, cls=GenericJSONEncoder), cls=GenericJSONDecoder)
In [39]: b.a
Out[39]: 'test'