鉴于您愿意打破封装,我认为这是您能做的最好的事情:
from pickle import Pickler
import os
class AtomicPickler(Pickler):
def __init__(self, protocol):
# You may want to replace this with a fake file object that just
# discards writes.
blackhole = open(os.devnull, 'w')
Pickler.__init__(self, blackhole, protocol)
self.depth = 0
def save(self, o):
self.depth += 1
if self.depth == 1:
return Pickler.save(self, o)
self.depth -= 1
return
def is_atomically_pickleable(o, protocol=None):
pickler = AtomicPickler(protocol)
try:
pickler.dump(o)
return True
except:
# Hopefully this exception was actually caused by dump(), and not
# something like a KeyboardInterrupt
return False
在 Python 中,判断某件事是否可行的唯一方法就是尝试它。这就是像 Python 这样动态的语言的本质。您的问题的困难在于您想要区分“顶层”的失败和更深层次的失败。
Pickler.save
本质上是 Python 的 pickling 逻辑的控制中心,因此上面创建了一个修改后的Pickler
忽略对其的递归调用save
方法。在顶级保存中引发的任何异常都将被视为酸洗失败。您可能想要添加限定符except
陈述。不合格excepts
在 Python 中,异常通常是一个坏主意,因为异常不仅用于程序错误,还用于诸如KeyboardInterrupt
and SystemExit
.
对于具有奇怪的自定义酸洗逻辑的类型,这可以给出可以说是假阴性的结果。例如,如果您创建一个自定义的类似列表的类,而不是导致Pickler.save
递归地调用它实际上尝试以某种方式自行腌制其元素,然后创建此类的一个实例,其中包含其自定义逻辑无法腌制的元素,is_atomically_pickleable
会回来False
对于本例,即使删除有问题的元素也会导致对象可腌制。
另外,请注意协议参数is_atomically_pickleable
。理论上,当使用不同的协议进行腌制时,对象的行为可能会有所不同(尽管这会很奇怪),因此您应该使其与您提供的协议参数相匹配dump
.