在python3下解开python2 datetime [英] Unpickling python2 datetime under python3

查看:121
本文介绍了在python3下解开python2 datetime的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我选择使用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
    then pickle._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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆