【问题标题】:Python3 pickle serialization with Cmd使用 Cmd 进行 Python3 泡菜序列化
【发布时间】:2016-12-26 18:19:14
【问题描述】:

我是 Python 新手,作为我的第一个项目,我正在尝试将 Python2 脚本转换为 Python3。

脚本在尝试使用 pickle 序列化类时失败。

当我试图保存一个使用 Cmd CLI 的类时,它似乎失败了。

此代码使用 Python2 工作。

谁能告诉我脚本出了什么问题以及如何修复它?

import sys
import cmd

try:
    import pickle as pickle
except:
    import pickle
import os.path

def main():    

        app = Labyrinth()
        turnfile = "turn0.lwot"
        app.Save(turnfile)

class CLI(cmd.Cmd):
    def __init__(self):
        cmd.Cmd.__init__(self)

class Labyrinth(cmd.Cmd):

    def __init__(self):
        cmd.Cmd.__init__(self)

    def Save(self, fname):
        with open(fname, 'wb') as f: 
            pickle.dump(self,f, 2)
        f.close()
        print ("Save Successful!")
        sys.exit()

if __name__ == '__main__':
    main()

【问题讨论】:

  • 导入泡菜作为泡菜包装在 try/except 中是什么意思?
  • @Turry - 我认为对于 python 2,import cPickle as pickle 输入错误。

标签: python-2.7 python-3.x serialization pickle


【解决方案1】:

并非所有对象都是可腌制的。特别是,文件对象是有问题的,因为您通常无法在以后恢复它们的状态。 cmd.Cmd 包含 stdinstdout 文件对象,这应该使它们不可拾取。我很惊讶它在 python 2 中工作,但它并没有真正......即使 stdinstdout 腌制,您稍后返回的未腌制对象也不起作用,如下例所示:

>>> import sys
>>> import pickle
>>> sys.stdout.write('foo\n')
foo
>>> serialized = pickle.dumps(sys.stdout, 2)
>>> stdout = pickle.loads(serialized)
>>> stdout.write('bar\n')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: I/O operation on closed file
>>> 

因此,即使这段代码没有失败,该对象也不应该在以后使用。您可以向对象添加一些特殊方法,这些方法可以让您修复对象,以便可以对它们进行序列化。在这里,我在保存时删除了坏属性,并在恢复时将它们添加回来。现在您可以腌制、解封,完成后它确实可以工作。

import sys
import cmd

try:
    import cPickle as pickle
except:
    import pickle
import os.path

def main():    

        app = Labyrinth()
        turnfile = "turn0.lwot"
        app.Save(turnfile)

class CLI(cmd.Cmd):
    def __init__(self):
        cmd.Cmd.__init__(self)

class Labyrinth(cmd.Cmd):

    def __init__(self):
        cmd.Cmd.__init__(self)

    def Save(self, fname):
        with open(fname, 'wb') as f: 
            pickle.dump(self,f, pickle.HIGHEST_PROTOCOL)
        f.close()
        print ("Save Successful!")
        sys.exit()

    def __getstate__(self):
        # stdin/out are unpicklable. We'll get new ones on load
        return tuple(((k,v) for k,v in self.__dict__.items()
            if k not in ('stdin', 'stdout')))

    def __setstate__(self, state):
        self.__dict__.update(state)
        self.stdin = sys.stdin
        self.stdout = sys.stdout


if __name__ == '__main__':
    main() 

【讨论】:

  • 谢谢你,它工作得很好,我在这个过程中学到了一些关于 python 酸洗和解酸的知识。
【解决方案2】:

使用协议没有帮助。完整的错误消息(您应该包括在内)是:

1027:~/mypy$ python3 stack41334887.py 
Traceback (most recent call last):
  File "stack41334887.py", line 33, in <module>
    main()
  File "stack41334887.py", line 14, in main
    app.Save(turnfile)
  File "stack41334887.py", line 27, in Save
    pickle.dump(self,f, 3, fix_imports=True)
TypeError: cannot serialize '_io.TextIOWrapper' object

Python3 对io 系统进行了一些重大更改。 TextIOWrapper 是 Py3 的新手。

https://docs.python.org/3.1/library/io.html#io.TextIOWrapper

Can I use multiprocessing.Pool in a method of a class? 在序列化TextIOWrapper 时也有问题。

=========

受到@tdelaney 的启发,我查看了stdin 的PY3 课程:

In [1212]: sys.stdin
Out[1212]: <_io.TextIOWrapper name='<stdin>' mode='r' encoding='UTF-8'>

所以这就是不能序列化的东西。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-03-13
    • 1970-01-01
    • 1970-01-01
    • 2021-12-13
    • 2021-05-08
    • 2019-11-13
    • 2020-08-16
    相关资源
    最近更新 更多