有没有办法腌制一个类定义?
我想做的是腌制定义(可以动态创建),然后通过 TCP 连接发送它,以便可以在另一端创建实例。
我了解可能存在依赖关系,例如该类所依赖的模块和全局变量。我也想在酸洗过程中捆绑这些,但我不关心自动检测依赖关系,因为如果用户有责任指定它们也没关系。
如果您使用dill
,它可以让您将其__main__
视为 python 模块(在大多数情况下)。因此,您可以序列化交互式定义的类等。 dill
也(默认情况下)可以将类定义作为泡菜的一部分传输。
>>> 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)
...
>>>
然后关闭解释器,并test.pkl
通过 TCP 发送文件。在您的远程机器上,现在您可以获得类实例。
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
>>>
但是如何获得类定义呢?所以这不是你想要的。然而,以下是。
>>> class MyTest2(object):
... def bar(self, x):
... return x*x + self.x
... x = 1
...
>>> import dill
>>> with open('test2.pkl', 'wb') as s:
... dill.dump(MyTest2, 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('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
因此,在 中dill
,有dill.source
, 并且具有可以检测函数和类的依赖关系的方法,并将它们与泡菜一起使用(大部分情况下)。
>>> def foo(x):
... return x*x
...
>>> class Bar(object):
... def zap(self, x):
... return foo(x) * self.x
... x = 3
...
>>> print dill.source.importable(Bar.zap, source=True)
def foo(x):
return x*x
def zap(self, x):
return foo(x) * self.x
所以这不是“完美的”(或者可能不是预期的)......但它确实序列化了动态构建方法的代码及其依赖项。您只是没有获得课程的其余部分 - 但在这种情况下不需要课程的其余部分。
如果你想得到一切,你可以腌制整个会话。
>>> 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
>>> 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
>>> dill.load_session('foo.pkl')
>>> b.x
11
>>> b.bar(2)
>>> b.x
15
>>> foo(3)
9
最后,如果您希望透明地为您“完成”传输,您可以使用pathos.pp
or 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
: https ://github.com/uqfoundation
唉,不是直接的。您可以发送语句的字符串形式或字节码形式,并在接收端class
使用“重新水化”它。exec
该文档很好地解释了什么可以腌制和不能腌制,以及为什么会这样。
http://docs.python.org/library/pickle.html#what-can-be-pickled-and-unpickled
基本上,如果类或模块在解压时可以按名称导入,那么它应该可以工作,除非您计划在现在和解压时更改类定义。在下面的类定义中,只有类名“Test”和方法名“mymethod”会被pickle。如果你挑选出类定义,然后更改定义,使 attr 是一个不同的值,而 mymethod 做了一些完全不同的事情,pickle 将选择新的定义。
class Test(object):
attr = 5
def mymethod(self, arg):
return arg