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 pickle逻辑的控制中心,因此上面创建了一个修改后的Pickler
,它忽略了对其save
方法的递归调用。在顶级保存中引发的任何异常都将被视为酸洗失败。您可能需要向except
语句添加限定符。Python中的非限定的excepts
通常是个坏主意,因为异常不仅用于程序错误,而且也用于KeyboardInterrupt
和{对于具有奇怪的自定义酸洗逻辑的类型,这可能会给出有争议的误报。例如,如果您创建了一个类似于自定义列表的类,该类并没有导致
Pickler.save
被递归调用,而是尝试以某种方式自行pickle其元素,然后创建了该类的一个实例,该实例包含其自定义逻辑无法pickle的元素,is_atomically_pickleable
将为此实例返回False
,即使删除有问题的元素将导致对象可pickle。在另外,请注意
is_atomically_pickleable
的协议参数。从理论上讲,一个对象在使用不同的协议进行pickle时会表现出不同的行为(尽管这会很奇怪),所以您应该使它与您给dump
的协议参数相匹配。在考虑到Python的动态特性,我认为除了启发式或白名单之外,没有一种定义良好的方法来完成您所要求的任务。在
如果我说:
x是“原子酸洗”吗?如果我说:
^{pr2}$是吗?x现在是“原子酸洗”了吗?在
如果我创建了一个始终具有lock属性的独立类会怎么样?如果我从一个实例中删除了那个属性呢?在
我认为persistent_id接口与您所尝试的不匹配。当你的对象应该引用新程序中的等效对象而不是旧程序的副本时,就可以使用它。你试图过滤掉所有不能被pickle的对象,这是不同的,你为什么要这么做。在
我认为这是你的代码有问题的迹象。您希望pickle引用gui小部件、文件和锁的对象,这表明您在做一些奇怪的事情。通常持久化的对象类型不应与该类型的对象相关或保持对该类对象的引用。在
话虽如此,我认为你最好的选择是:
这对于python实现应该有效,我不保证在C实现中会发生什么。保存的每个对象都将传递给save方法。此方法在无法pickling对象时将引发PicklingError。此时,您可以介入并调用该函数,要求它对您自己的对象进行pickle,该对象应该可以进行pickle。在
编辑
据我所知,实际上你有一个用户创建的对象字典。有些对象是可选择的,有些是不可选择的。我会这样做:
^{pr2}$当你想保存这个对象集合时,就使用这个字典。用户应该能够获取任何可选择的对象,但其他所有对象都将作为Unpicklable()对象返回。这种方法与前一种方法的区别在于,对象本身是可拾取的,但引用了不可拾取的对象。但不管怎样,这些东西很可能会破碎。在
这种方法还有一个好处,即它完全保留在定义的API中,因此可以在cPickle或pickle中工作。在
相关问题 更多 >
编程相关推荐