Подтвердить что ты не робот

Почему протокол pickle 2 позволяет мне сериализовать открытый файл?

Рассмотрим:

>>> import pickle
>>> thing = open('foobar.txt','w')
>>> pickle.dumps(thing)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python2.6/pickle.py", line 1366, in dumps
    Pickler(file, protocol).dump(obj)
  File "/usr/lib/python2.6/pickle.py", line 224, in dump
    self.save(obj)
  File "/usr/lib/python2.6/pickle.py", line 306, in save
    rv = reduce(self.proto)
  File "/usr/lib/python2.6/copy_reg.py", line 70, in _reduce_ex
    raise TypeError, "can't pickle %s objects" % base.__name__
TypeError: can't pickle file objects

Кажется вполне разумным - конечно, я не могу раскрыть открытый дескриптор файла. Но:

>>> pickle.dumps(thing, 2)
'\x80\x02c__builtin__\nfile\nq\x00)\x81q\x01.'
>>> pickle.loads(pickle.dumps(thing, 2))
<closed file '<uninitialized file>', mode '<uninitialized file>' at 0x7ff3c078>

По-видимому, я могу раскрыть открытый файл, просто не полезно.

Это намеренно? Это скрывало ошибку в моем коде, где я ошибочно травил объект, в котором находился файл. В некоторых условиях этот объект также содержит курсор pyodbc с тем же результатом.

Я ничего не вижу в PEP 307 об этом. Был ли это просто надзор, или есть что-то важное, что я пропал без вести, что может позволить мне получить исключение, которое я хочу, даже при травлении с использованием протокола 2?

Я использую Python 2.6.5. Я знаю, я знаю, но это то, что приходит с моим распределением.

4b9b3361

Ответ 1

В Python Wiki говорится:

Вы не можете раскрыть открытые файловые объекты, сетевые подключения или соединения с базой данных. Когда вы думаете об этом, это имеет смысл - разборки не могут подключиться к файловому объекту, когда вы расклеиваете свой объект, а процесс создания этого соединения выходит за рамки того, что рассол может автоматически сделать для вас. Если вы действительно хотите расчехлить что-то, что имеет атрибут, вызывающий проблемы, посмотрите на документацию рассола для __getstate__, __setstate__ и __getinitargs__ - с их помощью вы можете исключить проблемные атрибуты.

Однако я нашел этот отчет об ошибках, который указывает, что вы на самом деле можете рассортировать файловые объекты. Это кажется непреднамеренным. Он был исправлен в Python 3.2.

Вы могли бы увидеть, можете ли вы адаптировать этот патч к Python 2.6, если хотите предотвратить его. В противном случае вам просто нужно быть осторожным, что вы мариновали.

Ответ 2

Если вы ищете лучшее поведение, вы можете использовать dill... который не будет сериализовать файловые объекты, но знает, как сериализовать дескрипторы файлов. Поведение заключается в том, что если файл существует, dill укажет на десериализованный дескриптор файла на нем... и если файл не существует, то дескриптор файла будет закрыт.

Python 2.7.8 (default, Jul  3 2014, 05:59:29) 
[GCC 4.2.1 Compatible Apple Clang 4.1 ((tags/Apple/clang-421.11.66))] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import dill
>>>        
>>> thing = open('foobar.txt', 'w')
>>> thing
<open file 'foobar.txt', mode 'w' at 0x10e3c2c00>
>>> dill.loads(dill.dumps(thing))
<open file 'foobar.txt', mode 'w' at 0x10e3c2c90>
>>> 

Получить dill здесь: https://github.com/uqfoundation