考虑一下:
>>> 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>显然我可以清理一个打开的文件,但不是很有用。
这是故意的吗?它掩盖了我代码中的一个bug,我错误地酸洗了一个拥有文件的对象。在某些情况下,该对象还持有pyodbc游标,结果相同。
我在PEP 307上看不到任何关于它的东西。这只是一个疏忽,或者是我遗漏了一些重要的事情,即使在使用协议2进行酸洗时,也可以让我得到我想要的异常?
我使用的是Python 2.6.5。我知道,我知道,但这是我的发行版附带的。
发布于 2011-08-18 20:43:21
在Python Wiki上,它说
您不能选取打开的文件对象、网络连接或数据库连接。仔细想想,这是有道理的-- pickle不能在取消pickle对象的pickle时使文件对象的连接存在,并且创建该连接的过程超出了pickle可以自动为您做的事情。如果您确实想要剔除具有导致问题的属性的对象,请查看
__getstate__、__setstate__和__getinitargs__的剔除文档--使用这些文档可以排除有问题的属性。
然而,我发现了this bug report,它表明您实际上可以 pickle文件对象。这看起来确实是无意的。在Python 3.2中已经修复了这个问题。
如果你想防止这种情况的发生,你可以看看你是否可以将这个补丁改编到Python2.6。否则,你只需要小心你腌制的东西。
发布于 2014-07-18 02:34:35
如果你正在寻找更好的行为,你可以使用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
https://stackoverflow.com/questions/7107409
复制相似问题