2016-12-26 2 views
1

Я новичок в Python, и в качестве своего первого проекта я пытаюсь преобразовать скрипт Python2 в Python3.Python3 pickle serialization с Cmd

Сценарий не работает, когда он пытается сериализовать класс, используя 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() 
+0

Что такое импортный рассол, как рассол, завернутый в попытку/исключение? –

+0

@Turry - я думаю, что это ошибка 'import cPickle as pickle' для python 2. – tdelaney

ответ

0

Воспроизведение протокола не помогает. Сообщение полной ошибки (которую вы должны были включены) является:

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.

=========

Так inspireed по @tdelaney, я проверил stdin для моей PY3 сессии:

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

Так что это вещь, которая не может быть сериализации.

2

Не все объекты гранулированы. В частности, файловые объекты проблематичны, потому что вы не можете восстановить их состояние позже. cmd.Cmd содержит stdin и stdout файловых объектов, что должно сделать их непригодными. Я был очень удивлен тем, что он работал в Python 2, но это не очень ... Даже хотя stdin и stdout маринованные, то unpickled объект вы получите позже не работает, так как в этом примере:

>>> 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() 
+0

Благодарим за это, это работает красиво, и я узнал справедливую бит о травлении питона и рассыпании в процессе. – gasha1