有没有办法让python的pickle忽略“这不是同一个对象”的错误?
有没有办法让 Python 的 pickle 忽略 "它不是同一个对象" 的错误呢?
我正在写一个测试,使用 Mock 来精确控制 datetime.utcnow() 产生的结果。因为我的代码对时间很敏感,所以使用 Mock 的 patch 功能可以让我更方便地进行测试。
这些测试需要把对象进行序列化(也就是 pickle),然后把结果发送到远程服务器。为了测试的目的,如果一个标准的 datetime 被序列化并且被远程服务器接收到,那就没问题了。
可惜的是,pickle 模块报了以下错误:
无法序列化 <type 'datetime.datetime'>: 它不是同一个对象,和 datetime.datetime 不一样
下面是一个简单的例子,可以复现这个错误。
from mock import patch
from datetime import datetime
import pickle
class MockDatetime(datetime):
frozendt = datetime(2011,05,31)
@classmethod
def advance(cls, **kw):
cls.frozendt = cls.frozendt + timedelta(**kw)
@classmethod
def utcnow(cls):
return cls.frozendt
@patch('datetime.datetime', MockDatetime)
def test():
pickle.dumps(datetime.utcnow())
if __name__ == '__main__':
test()
有没有什么组合,比如 __reduce__
和 __getstate__
方法,可以让 pickle 误以为 MockDatetime 是一个 datetime,当我进行序列化的时候?
2 个回答
5
如果有人想要一个通用的方法来保存模拟对象(mock)的状态:
m = mock.MagicMock()
m.__reduce__ = lambda self: (mock.MagicMock, ())
请注意,这个方法似乎并不能保存模拟对象内部的内容,比如调用记录。
6
在文档的“在哪里打补丁”部分,我看到有这样的建议:
基本原则是,你应该在对象被使用的地方打补丁,这个地方不一定和对象被定义的地方是一样的。
根据这个建议,我尝试把:
@patch('datetime.datetime', MockDatetime)
替换成:
@patch('__main__.datetime', MockDatetime)
而且,我没有从pickle
那里收到任何错误。此外,我还加了一个print
语句,以确保datetime
确实被打了补丁,结果得到了预期的值。