【问题标题】:python: pickle misbehaving in django shell as opposed to python shell?python:与python shell相比,django shell中的pickle行为不端?
【发布时间】:2014-06-16 14:27:53
【问题描述】:

作为来自my previous question 的另一个问题,结果表明,与 python shell 相比,pickle 在 django shell 中的行为不同......

这个脚本:

import pickle

class TestObj(object): pass
testobj = TestObj()
pickled = pickle.dumps(testobj, pickle.HIGHEST_PROTOCOL)

在 python shell 中可以正常工作,但在 django shell 中会按照PicklingError: Can't pickle <class 'TestObj'>: attribute lookup __builtin__.TestObj failed 的行引发PickleError

有人能在这里解释这个问题吗?如果可能,将其链接回我之前的问题?

【问题讨论】:

  • 听起来像pickle找不到Django shell中创建的TestObj;它的环境设置与解释器略有不同。具体来说,__name__ 似乎有所不同。
  • 有趣。那么这种行为是否也扩展到实际的 django 进程?如果您查看我之前的问题,我在测试期间很难将 Mock() 对象存储在 django 的 LocMemCache 中,并假设它是由与 shell 中发生的相同 PickleError 引起的,但也许不是?
  • 不,在酸洗时,pickle 模块只存储即时数据以及再次导入类的位置。它将测试是否可以为此导入该类,并且由于似乎设置了 Django 交互式提示的方式,该测试失败(TestObj.__module__ 显然指向__builtin__)。
  • 在常规 Django 进程中,设置不是“特殊”的。使用“可导入”的对象对此进行测试。在交互提示中,将其存储在另一个模块上,并重新指向__module__import somemodulesomemodule.TestObj = TestObjTestObj.__module__ = 'somemodule' 将向 Python 假装 from somemodule import TestObj 是重新导入类的规范方法。
  • 我明白了,所以看起来我使用 Mock 得到了一个完全不同的 PicklingError,它本身就很神秘:PicklingError: Can't pickle <class 'mock.Mock'>: it's not the same object as mock.Mock

标签: python django pickle


【解决方案1】:

pickle 将确保它可以重新导入一个类,因为只有实例本身的数据被腌制,加上类的导入位置。因此,pickle 在类中查找 __module__ 属性以确定它的来源。

Django 交互环境似乎没有设置这个__module__ 属性;因此TestObj.__module__ 是从object 基类继承而来的,那就是__builtin__。也许没有设置__name__ global。结果,pickle 模块最终会为您的课程寻找错误的位置。毕竟没有__builtin__.TestObj

从 cmets 中,我了解到您正在尝试将模拟对象存储在 Django 缓存中。这行不通,就像mock objects are not pickleable。这是有道理的,就像在 unpickling (可能在一个全新的 Python 进程中)一样,pickle 怎么知道正在模拟的原始类是什么?

【讨论】:

    【解决方案2】:

    你能不能只使用一个不通过引用腌制类的序列化程序……然后预序列化你传递到 django 缓存中的内容?这不仅会存储实例,还会存储类定义本身——这应该允许您在任何地方重建实例。

    查看我对您最初问题的回答: Pickle can't store an object in django locmem cache during tests?

    我对 django Mock 对象一无所知,或者它们是否有一些特别不可取的东西......但只要它们是用 python 代码构建的(而不是用 C 语言构建的,并且有一个薄的 python 包装层),那么以上应该可以工作。

    【讨论】:

      猜你喜欢
      • 2013-08-03
      • 2010-10-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-03-04
      • 1970-01-01
      相关资源
      最近更新 更多