[英]Pickle class instance plus definition?
這是一個我懷疑很常見的問題,但我還沒有找到解決方案。 我想要的很簡單,而且在技術上似乎可行:我有一個簡單的 python class,我想將它存儲在磁盤上,實例和定義,在一個文件中。 Pickle 將存儲數據,但不存儲 class 定義。 有人可能會爭辯說 class 定義已經存儲在 my.py 文件中,但我不想要單獨的.py 文件; 我的目標是擁有一個獨立的單個文件,我可以用一行代碼將它彈回我的命名空間。
所以是的,我知道這可能使用兩個文件和兩行代碼,但我希望它在一個文件和一行代碼中。 原因是因為我經常發現自己處於這種情況; 我正在處理一些大數據集,在 python 中對其進行操作,然后必須將切片、切塊和轉換后的數據寫回到一些預先存在的目錄結構中。 我不想在這些數據目錄中亂扔亂七八糟的 python class 存根以保持我的代碼和數據相關聯,而我更想要的是跟蹤和組織所有這些定義的小臨時類的麻煩在腳本中獨立運行。
因此,便利性不在於代碼的可讀性,而在於代碼和數據之間毫不費力且不可篡改的關聯。 這對我來說似乎是一個有價值的目標,盡管我知道這在大多數情況下是不合適的。
所以問題是:有沒有做這種事情的 package 或代碼片段,因為我似乎找不到任何東西。
如果您使用dill
,它可以讓您將__main__
視為 python 模塊(在大多數情況下)。 因此,您可以序列化交互式定義的類等。 dill
也(默認情況下)可以傳輸 class 定義作為泡菜的一部分。
>>> 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
。 在您的遠程機器上,現在您可以獲得 class 實例。
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 定義? 所以這不是你想要的。 然而,以下是。
>>> 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)
...
>>>
然后發送文件后……你可以得到 class 定義。
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
既然你在尋找一個班輪,我可以做得更好。 我沒有顯示您可以同時發送 class 和實例,也許這就是您想要的。
>>> 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 一起使用(大部分情況下)。
>>> 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
所以這不是“完美的”(或者可能不是預期的)......但它確實序列化了動態構建方法的代碼及其依賴項。 您只是沒有得到 class 的 rest - 但在這種情況下不需要 ZA2F2ED4F8DCECC2CBB4DZ21A 的 rest。 不過,這似乎不是你想要的。
如果你想得到所有東西,你可以腌制整個 session。 並在一行中(兩個計算import
)。
>>> 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
最后,如果您希望透明地為您“完成”傳輸(而不是使用文件),您可以使用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
: https://github.com/uqfoundation
泡菜不能泡菜 python 代碼,所以我認為泡菜根本不可能。
>>> 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
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.