Python Pickle类实例加定义?

Python Pickle类实例加定义?,python,pickle,Python,Pickle,我怀疑这是一个常见的问题,但我还没有找到解决办法。我想要的非常简单,而且在技术上似乎是可行的:我有一个简单的python类,我想将它存储在一个文件中的光盘、实例和定义中。Pickle将存储数据,但不存储类定义。有人可能会说,类定义已经存储在我的.py文件中,但我不想要一个单独的.py文件;我的目标是拥有一个独立的文件,我可以用一行代码将其弹出回我的命名空间 是的,我知道这可能需要两个文件和两行代码,但我希望它包含在一个文件和一行代码中。原因是我经常发现自己处于这种情况;我正在处理一些大数据集,用

我怀疑这是一个常见的问题,但我还没有找到解决办法。我想要的非常简单,而且在技术上似乎是可行的:我有一个简单的python类,我想将它存储在一个文件中的光盘、实例和定义中。Pickle将存储数据,但不存储类定义。有人可能会说,类定义已经存储在我的.py文件中,但我不想要一个单独的.py文件;我的目标是拥有一个独立的文件,我可以用一行代码将其弹出回我的命名空间

是的,我知道这可能需要两个文件和两行代码,但我希望它包含在一个文件和一行代码中。原因是我经常发现自己处于这种情况;我正在处理一些大数据集,用python操作它,然后不得不将切片、切块和转换后的数据写回一些预先存在的目录结构。我不想在这些数据目录中乱扔一些命名不正确的python类存根,以保持代码和数据的关联,我更不想看到的是跟踪和组织所有这些在脚本中动态定义的临时类的麻烦

因此,方便性并不在于代码的可读性,而是在于代码和数据之间的轻松且不令人费解的关联。对我来说,这似乎是一个有价值的目标,尽管我知道这在大多数情况下并不合适


所以问题是:是否有一个包或代码片段可以做这样的事情,因为我似乎找不到任何包或代码片段。

Pickle不能Pickle python代码,所以我认为Pickle根本不可能做到这一点

>>> from pickle import *
>>> def A(object):
...     def __init__(self):
...             self.potato = "Hello"
...             print "Starting"
...                                                                                                                                                                  
>>> A.__code__                                                                                                                                                       
<code object A at 0xb76bc0b0, file "<stdin>", line 1>                                                                                                                
>>> dumps(A.__code__)                                                                                                                                                
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 code objects
来自pickle导入的
>>*
>>>定义A(对象):
...     定义初始化(自):
...             self.potato=“你好”
...             打印“开始”
...                                                                                                                                                                  
>>>A.。__代码_;
<0xb76bc0b0处的代码对象A,文件“stdin”,第1行>
>>>转储(A.\uuuu代码\uuuu)
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
文件“/usr/lib/python2.6/pickle.py”,第1366行,转储
Pickler(文件,协议).dump(obj)
文件“/usr/lib/python2.6/pickle.py”,第224行,在转储中
自我保存(obj)
文件“/usr/lib/python2.6/pickle.py”,第306行,保存
rv=减少(自编程)
文件“/usr/lib/python2.6/copy_reg.py”,第70行,在
raise TypeError,“无法pickle%s对象”%base.\u\n__
TypeError:无法pickle代码对象

如果您使用dill,它使您能够将
\uuuu main\uuuu
视为python模块(大部分情况下)。因此,可以序列化交互定义的类等
dill
也可以(默认情况下)将类定义作为pickle的一部分进行传输

>>> class MyTest(object):
...   def foo(self, x):
...     return self.x * x
...   x = 4
... 
>>> f = MyTest() 
>>> import dill
>>>
>>> with open('test.pkl', 'wb') as s:
...   dill.dump(f, s)
... 
>>> 
然后关闭解释器,并通过TCP发送文件
test.pkl
。在远程计算机上,现在可以获取类实例

Python 2.7.9 (default, Dec 11 2014, 01:21:43) 
[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
>>> with open('test.pkl', 'rb') as s:
...   f = dill.load(s)
... 
>>> f
<__main__.MyTest object at 0x1069348d0>
>>> f.x
4
>>> f.foo(2)
8
>>>             
然后在发送文件之后…您可以获得类定义

Python 2.7.9 (default, Dec 11 2014, 01:21:43) 
[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
>>> with open('test2.pkl', 'rb') as s:
...   MyTest2 = dill.load(s)
... 
>>> print dill.source.getsource(MyTest2)
class MyTest2(object):
  def bar(self, x):
    return x*x + self.x
  x = 1

>>> f = MyTest2()
>>> f.x
1
>>> f.bar(4)
17
既然你在找一条一行,我可以做得更好。我没有告诉你可以同时发送类和实例,也许这就是你想要的

>>> import dill
>>> class Foo(object): 
...   def bar(self, x):
...     return x+self.x
...   x = 1
... 
>>> b = Foo()
>>> b.x = 5
>>> 
>>> with open('blah.pkl', 'wb') as s:
...   dill.dump((Foo, b), s)
... 
>>> 
它仍然不是一条线,但是,它可以工作

Python 2.7.9 (default, Dec 11 2014, 01:21:43) 
[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
>>> with open('blah.pkl', 'rb') as s:
...   Foo, b = dill.load(s)
... 
>>> b.x  
5
>>> Foo.bar(b, 2)
7
因此,
dill
中有
dill.source
,它的方法可以检测函数和类的依赖关系,并将它们与pickle一起使用(大部分情况下)

所以这不是“完美的”(或者可能不是预期的)…但它确实序列化了动态构建的方法及其依赖项的代码。您无法获得类的其余部分,但在这种情况下不需要类的其余部分。不过,这似乎不是你想要的

如果你想得到一切,你可以把整个课程都泡菜。 并且在中有一行(两行计算
导入

然后在远程机器上

Python 2.7.9 (default, Dec 11 2014, 01:21:43) 
[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
>>> # the one line
>>> dill.load_session('foo.pkl')
>>> b.x
11
>>> b.bar(2)
>>> b.x
15
>>> foo(3)
9
最后,如果希望透明地“完成”传输(而不是使用文件),可以使用
pathos.pp
ppft
,它们提供将对象发送到第二台python服务器(远程机器上)或python进程的能力。他们在引擎盖下使用
dill
,只需将代码穿过电线即可

>>> class More(object):
...   def squared(self, x):
...     return x*x
... 
>>> import pathos
>>> 
>>> p = pathos.pp.ParallelPythonPool(servers=('localhost,1234',))
>>> 
>>> m = More()
>>> p.map(m.squared, range(5))
[0, 1, 4, 9, 16]
servers
参数是可选的,这里只是连接到端口
1234
上的本地计算机……但是如果您使用远程计算机名称和端口(或者同时使用),您将启动远程计算机--“毫不费力”


获取
dill
pathos
ppft
这里:

我建议避免长期数据存储的pickle:它非常脆弱。尝试将
dict
与json一起使用,或将HDF5与Python一起使用。这并没有回答你的问题,所以这只是一个评论,但我诚实地认为这是一个更可行的长期解决方案。嗯,我一直在寻找的正是自我记录的长期性质。注意,代码不变是整个方案不可分割的一部分;我写了一些东西,一个月后想检查一下;最初的脚本可能已经不存在了,但取回myobject.myattribute应该是plney self doc
>>> import dill
>>> def foo(x):
...   return x*x
... 
>>> class Blah(object):
...   def bar(self, x):
...     self.x = (lambda x:foo(x)+self.x)(x)
...   x = 2
... 
>>> b = Blah()
>>> b.x
2
>>> b.bar(3)
>>> b.x
11
>>> # the one line
>>> dill.dump_session('foo.pkl')
>>> 
Python 2.7.9 (default, Dec 11 2014, 01:21:43) 
[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
>>> # the one line
>>> dill.load_session('foo.pkl')
>>> b.x
11
>>> b.bar(2)
>>> b.x
15
>>> foo(3)
9
>>> class More(object):
...   def squared(self, x):
...     return x*x
... 
>>> import pathos
>>> 
>>> p = pathos.pp.ParallelPythonPool(servers=('localhost,1234',))
>>> 
>>> m = More()
>>> p.map(m.squared, range(5))
[0, 1, 4, 9, 16]