【问题标题】:How to check if an object is pickleable如何检查对象是否可腌制
【发布时间】:2013-07-26 02:47:51
【问题描述】:

我有一个我想腌制的各种类型的对象列表。我只想腌制那些可腌制的。除了尝试腌制之外,是否有标准方法来检查对象是否为可腌制类型?

文档说如果发生酸洗异常,可能是在某些字节已写入文件之后,因此尝试酸洗对象作为测试似乎不是一个好的解决方案。

我看到了this post,但它没有回答我的问题。

【问题讨论】:

  • 尝试将其写入文件可能是一种解决方案。只是不要将其写入您的真实输出文件,而是其他地方。到 /dev/null 或某处。
  • 以下是腌制的规则:docs.python.org/3/library/…
  • 为什么当 dill 拥有你想要的dill.pickles(f) 功能时,你接受了鸭子打字的答案?
  • 我点赞duckdill.pickles 答案,因为它提供了更多详细信息和进一步阅读。但是 OP 可能选择了它,因为泡菜的答案是在鸭子打字答案后 2 年出现的。

标签: python pickle


【解决方案1】:

dill package 中的 dill.pickles 方法就是这样做的。

>>> class Foo(object):
...   x = iter([1,2,3])
... 
>>> f = Foo()     
>>> 
>>> dill.pickles(f)
False

我们可以使用dill中的方法来查找导致失败的原因。

>>> dill.detect.badtypes(f)
<class '__main__.Foo'>
>>> dill.detect.badtypes(f, depth=1)
{'__setattr__': <type 'method-wrapper'>, '__reduce_ex__': <type 'builtin_function_or_method'>, '__reduce__': <type 'builtin_function_or_method'>, '__str__': <type 'method-wrapper'>, '__format__': <type 'builtin_function_or_method'>, '__getattribute__': <type 'method-wrapper'>, '__class__': <type 'type'>, '__delattr__': <type 'method-wrapper'>, '__subclasshook__': <type 'builtin_function_or_method'>, '__repr__': <type 'method-wrapper'>, '__hash__': <type 'method-wrapper'>, 'x': <type 'listiterator'>, '__sizeof__': <type 'builtin_function_or_method'>, '__init__': <type 'method-wrapper'>}
>>> dill.detect.badtypes(f, depth=1).keys()
['__setattr__', '__reduce_ex__', '__reduce__', '__str__', '__format__', '__getattribute__', '__class__', '__delattr__', '__subclasshook__', '__repr__', '__hash__', 'x', '__sizeof__', '__init__']

所以,唯一失败的不是类的“内置”方法是x...所以这是一个很好的起点。让我们检查一下“x”,如果有问题,则将其替换为其他内容。

>>> dill.pickles(Foo.x)
False
>>> Foo.x = xrange(1,4)
>>> dill.pickles(Foo.x)
True

是的,x 导致了故障,用xrange 替换它是可行的,因为dill 可以腌制xrange。还剩下什么?

>>> dill.detect.badtypes(f, depth=1).keys()
[]
>>> dill.detect.badtypes(f, depth=1)       
{}
>>> dill.pickles(f)                 
True
>>> 

显然(可能是因为 __dict__ 类中对 x 的引用现在腌制了),f 现在腌制了……所以我们完成了。

dill 还提供了trace 来显示酸洗对象的确切路径。

>>> dill.detect.trace(True)
>>> dill.pickles(f)
T2: <class '__main__.Foo'>
F2: <function _create_type at 0x10e79b668>
T1: <type 'type'>
F2: <function _load_type at 0x10e79b5f0>
T1: <type 'object'>
D2: <dict object at 0x10e7c6168>
Si: xrange(1, 4)
F2: <function _eval_repr at 0x10e79bcf8>
D2: <dict object at 0x10e7c6280>
True

【讨论】:

  • 当我尝试这个时,我得到了很多函数,我更不确定从哪里开始(腌制一个类,它似乎返回所有子方法)
  • @Roelant:我假设当你说你“试试这个”时,你的意思是你在看跟踪。酸洗是递归的,因此您会看到很多“子对象”。每次看到F2D1 之类的标记时,就会打开另一个“子对象”进行检查,并且在对象实际被腌制时有一个类似的结束标记。
【解决方案2】:

我建议在这种情况下进行 duck 测试。尝试pickle到一个临时文件或内存文件中,如果你觉得合适的话,如果失败则丢弃结果,如果成功则重命名。

为什么?

在python中,你可以通过两种方式检查对象是否具有某些属性。

检查对象是否是某个Abstract Base Class 的实例。例如。 Number "数字层次结构的根。如果您只想检查参数 x 是否为数字,而不关心是什么类型,请使用 isinstance(x, Number)。"

或者尝试一下,然后处理异常。这发生在很多场合。 pythonic 哲学基于鸭子Duck typingduck testEAFP 是关键字。

我什至相信在社区的压力下,python3 已经正确引入了第一个,而许多人仍然坚信 duck 是使用 python 的方式。

AFAIK 没有可以检查的特殊先决条件,也没有任何ABC 在酸洗的情况下可以检查该对象。所以剩下的就是duck了。

也许可以尝试其他方法,但可能不值得。人工自省很难初步判断是否适合酸洗。

【讨论】:

  • 谢谢,我熟悉python鸭测试。让我感到惊讶的是,没有更好的方法来检查可腌制性。每个可腌制对象都需要实现某些方法吗?我们不能直接对其中一种方法进行测试吗?
  • 好吧,当我第一次偶然发现它时,我感到很困惑。我需要检查对象是否可迭代。我找到的最简单的方法是try: mock = iter(data[0]) except TypeError:。而且它完全反对某些 python 方式,因为理想情况下我应该将它视为可迭代并进一步传递。但是,这有一个严重的缺点,即错误弹出太低而无法轻易找到它们。根据我在文档中读到的内容,python 使用其内部知识来腌制对象。它不像__str__。你可以在奇怪的情况下提供一些帮助,但它们并不是到处都是必需的。我没有找到任何其他可靠的方法。
  • 这就解释了,谢谢。在我看来仍然是一个奇怪的设计选择 - 但我可能没有看到这方面的所有角度。
  • @Bitwise Pickling 是一个复杂的,也许更重要的是,递归 过程,它在很大程度上取决于范围内的内容。请记住,Python 是一种动态语言,因此“什么在哪里”根本不是一个容易问的问题,而且确实可以改变答案。所以事实上,确定一个对象是否可腌制的唯一可能方法是尝试腌制它。实际上,一个完美的isPickleable() 可能需要解决停机问题。
【解决方案3】:

dill 允许腌制比内置 pickle 更多的东西。

我认为这应该做你想做的事:

def is_picklable(obj):
  try:
    pickle.dumps(obj)

  except pickle.PicklingError:
    return False
  return True

【讨论】:

  • 除此之外没有官方API吗?错误处理可能很慢/很昂贵...
猜你喜欢
  • 1970-01-01
  • 2015-11-01
  • 1970-01-01
  • 2011-04-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-04-14
相关资源
最近更新 更多