在python3下解开python2 datetime [英] Unpickling python2 datetime under python3
问题描述
我选择使用pickle(+ base64 + TCP套接字)在我的python3代码和旧版python2代码之间通信数据,但是我遇到了datetime
对象的问题:
I chose to use pickle (+base64+TCP sockets) to communicate data between my python3 code and legacy python2 code, but I am having trouble with datetime
objects:
PY3对象在PY2上的修补效果很好,但是在调用datetime构造函数时反之则引发TypeError
,然后在load_reduce函数中引发UnicodeEncodeError
.
The PY3 object unpickles well on PY2, but the reverse raises a TypeError
when calling the datetime constructor, then a UnicodeEncodeError
in the load_reduce function.
简短的测试程序和要点
-
我在PY2中使用
pickle.dumps(reply, protocol=2)
,然后在PY3中使用pickle._loads(pickled, fix_imports=True, encoding='latin1')
(尝试None和utf-8都没有成功)
I am using
pickle.dumps(reply, protocol=2)
in PY2
thenpickle._loads(pickled, fix_imports=True, encoding='latin1')
in PY3
(tried None and utf-8 without success)
本地cPickle loads
解码也失败,我仅使用纯python的_loads
进行调试.
Native cPickle loads
decoding fails too, I am only using pure python's _loads
for debugging.
这是datetime
错误吗?也许datetime.__getstate__/__setstate__
实现不兼容?
Is this a datetime
bug ? Maybe datetime.__getstate__/__setstate__
implementations are not compatible ?
欢迎对代码发表任何评论...
Any remark on the code is welcome...
PY-3.4.0泡菜:
PY-3.4.0 pickle:
0: \x80 PROTO 2
2: c GLOBAL 'datetime datetime'
21: q BINPUT 0
23: c GLOBAL '_codecs encode'
39: q BINPUT 1
41: X BINUNICODE u'\x07\xde\x07\x11\x0f\x06\x11\x05\n\x90'
58: q BINPUT 2
60: X BINUNICODE u'latin1'
71: q BINPUT 3
73: \x86 TUPLE2
74: q BINPUT 4
76: R REDUCE
77: q BINPUT 5
79: \x85 TUPLE1
80: q BINPUT 6
82: R REDUCE
83: q BINPUT 7
85: . STOP
PY-2.7.6咸菜:
PY-2.7.6 pickle:
0: \\x80 PROTO 2
2: c GLOBAL 'datetime datetime'
21: q BINPUT 0
23: U SHORT_BINSTRING '\\x07\xc3\x9e\\x07\\x11\\x0f\\x06\\x11\\x05\\n\\x90'
35: q BINPUT 1
37: \\x85 TUPLE1
38: q BINPUT 2
40: R REDUCE
41: q BINPUT 3
43: ] EMPTY_LIST
44: q BINPUT 4
46: N NONE
47: \\x87 TUPLE3
48: q BINPUT 5
50: . STOP
PY-3.4.0 pickle.load_reduce
:
PY-3.4.0 pickle.load_reduce
:
def load_reduce(self):
stack = self.stack
args = stack.pop()
func = stack[-1]
try:
value = func(*args)
except:
print(sys.exc_info())
print(func, args)
raise
stack[-1] = value
dispatch[REDUCE[0]] = load_reduce
PY-3.4.0 datetime
泡菜支持:
PY-3.4.0 datetime
pickle support:
# Pickle support.
def _getstate(self):
yhi, ylo = divmod(self._year, 256)
us2, us3 = divmod(self._microsecond, 256)
us1, us2 = divmod(us2, 256)
basestate = bytes([yhi, ylo, self._month, self._day,
self._hour, self._minute, self._second,
us1, us2, us3])
if self._tzinfo is None:
return (basestate,)
else:
return (basestate, self._tzinfo)
def __setstate(self, string, tzinfo):
(yhi, ylo, self._month, self._day, self._hour,
self._minute, self._second, us1, us2, us3) = string
self._year = yhi * 256 + ylo
self._microsecond = (((us1 << 8) | us2) << 8) | us3
if tzinfo is None or isinstance(tzinfo, _tzinfo_class):
self._tzinfo = tzinfo
else:
raise TypeError("bad tzinfo state arg %r" % tzinfo)
def __reduce__(self):
return (self.__class__, self._getstate())
推荐答案
解决方法是像这样使用encoding="bytes"
:
The workaround is to use the encoding="bytes"
like this:
pickled_bytes = bytes(pickled_str, encoding='latin1') # If your input is a string(not my case)
data = pickle.loads(pickled_bytes, encoding='bytes')
(感谢蒂姆·彼得斯的建议)
(Thanks to Tim Peters for the suggestion)
问题仍然在 http://bugs.python.org/issue22005 上打开,以了解原因必填.
Issue still opened at http://bugs.python.org/issue22005 as to why this is required.
这篇关于在python3下解开python2 datetime的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!