PicklingError:无法序列化<class ...>:与...不是同一对象在GAE中

2 投票
2 回答
12149 浏览
提问于 2025-04-17 10:52

我在我的GAE Python应用中遇到了一个PicklingError错误,出现在这行代码:

deferred.defer(email_voters_begin, ekey, voter_list)

这三个参数分别是:

  • email_voters_begin -- 这是一个Python函数,比如说,function email_voters_begin在内存中的地址是0x1035d4488
  • ekey -- 这是我定义的一个实体的键,比如说,它的值是agdvcGF2b3Rlcg4LEghFbGVjdGlvbhgCDA
  • voter_list -- 这是我定义的一个对象列表,比如说,它的内容是[models.Voter对象在内存中的地址是0x103d3d310, ... ]

当这行代码在我的测试中执行时(使用webtest和nosegae),我遇到了以下错误:

Traceback (most recent call last):
  [...]
  File "/Users/joneill/OpenSTV/OpenSTV/trunk/OpaVote-HR/tasks.py", line 29, in init_voters_and_send_email
    deferred.defer(email_voters_begin, ekey, voter_list)
  File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/ext/deferred/deferred.py", line 249, in defer
    pickled = serialize(obj, *args, **kwargs)
  File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/ext/deferred/deferred.py", line 221, in serialize
    return pickle.dumps(curried, protocol=pickle.HIGHEST_PROTOCOL)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 1374, in dumps
    Pickler(file, protocol).dump(obj)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 224, in dump
    self.save(obj)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 286, in save
    f(self, obj) # Call unbound method with explicit self
  [...]
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 331, in save
    self.save_reduce(obj=obj, *rv)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 396, in save_reduce
    save(cls)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 286, in save
    f(self, obj) # Call unbound method with explicit self
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 753, in save_global
    (obj, module, name))
PicklingError: Can't pickle <class 'google.appengine.ext.blobstore.blobstore.BlobInfo'>: it's not the same object as google.appengine.ext.blobstore.blobstore.BlobInfo

需要注意的是,传入deferred.defer()Voter实体并没有BlobReference属性,但这些Voter实体确实有一个ReferenceProperty指向另一个实体,而那个实体是有BlobReference属性的。我本以为没有任何BlobInfo对象会被包含在pickle中,但错误提示似乎有一个被包含了。

当我在浏览器窗口中使用开发服务器运行相同的代码时,这个错误就不会出现。

我对如何调试这个问题感到困惑,任何建议都非常感谢。

2 个回答

1

你绝对不要把模型的实例传给一个延迟处理的地方。应该使用键值来代替:

deferred.defer(email_voters_begin, ekey, [v.key() for v in voter_list])

在你的 email_voters_begin 里:

def email_voters_begin(ekey, voters_keys):
    voter_list = models.Voter.get(voters_keys)
1

这个问题可能是因为你在至少一个投票者对象上获取了ReferenceProperty。一旦你取消了对ReferenceProperty的引用,模型实例就会把它缓存起来。序列化的时候,也会把任何缓存的对象一起处理,所以它试图把Voter实例、被引用的实例和它的BlobInfo都序列化。

一般来说,正如Skirmantas所说,把模型实例传给延迟处理通常不是个好主意。如果可以的话,应该传递键值。如果不行,就把实例序列化成协议缓冲区(Protocol Buffers),然后传递这些。

撰写回答