Python:检查对象是否是原子pickleab

2024-10-01 13:25:47 发布

您现在位置:Python中文网/ 问答频道 /正文

检查一个对象是否可以被原子化酸洗的准确方法是什么?当我说“原子酸洗”时,我的意思是不考虑它可能涉及的其他对象。例如,此列表:

l = [threading.Lock()]

不是可pickle对象,因为它引用了不可pickle的Lock。但从原子论的角度来看,这个列表本身是可以腌制的。在

那么如何检查一个对象是否是原子可酸洗的呢?(我想应该对班级进行检查,但我不确定。)

我希望它表现得像这样:

^{pr2}$

等等


Tags: 对象方法lock列表pickle角度threading原子
3条回答

鉴于您愿意打破封装,我认为这是您能做的最好的方法:

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 = object()

x是“原子酸洗”吗?如果我说:

^{pr2}$

是吗?x现在是“原子酸洗”了吗?在

如果我创建了一个始终具有lock属性的独立类会怎么样?如果我从一个实例中删除了那个属性呢?在

我认为persistent_id接口与您所尝试的不匹配。当你的对象应该引用新程序中的等效对象而不是旧程序的副本时,就可以使用它。你试图过滤掉所有不能被pickle的对象,这是不同的,你为什么要这么做。在

我认为这是你的代码有问题的迹象。您希望pickle引用gui小部件、文件和锁的对象,这表明您在做一些奇怪的事情。通常持久化的对象类型不应与该类型的对象相关或保持对该类对象的引用。在

话虽如此,我认为你最好的选择是:

class MyPickler(Pickler):
    def save(self, obj):
        try:
             Pickler.save(self, obj)
        except PicklingEror:
             Pickle.save( self, FilteredObject(obj) )

这对于python实现应该有效,我不保证在C实现中会发生什么。保存的每个对象都将传递给save方法。此方法在无法pickling对象时将引发PicklingError。此时,您可以介入并调用该函数,要求它对您自己的对象进行pickle,该对象应该可以进行pickle。在

编辑

据我所知,实际上你有一个用户创建的对象字典。有些对象是可选择的,有些是不可选择的。我会这样做:

^{pr2}$

当你想保存这个对象集合时,就使用这个字典。用户应该能够获取任何可选择的对象,但其他所有对象都将作为Unpicklable()对象返回。这种方法与前一种方法的区别在于,对象本身是可拾取的,但引用了不可拾取的对象。但不管怎样,这些东西很可能会破碎。在

这种方法还有一个好处,即它完全保留在定义的API中,因此可以在cPickle或pickle中工作。在

相关问题 更多 >