9

クラス定義をピクルする方法はありますか?

私がやりたいのは、定義をピクルして (動的に作成される可能性があります)、TCP 接続を介して送信し、インスタンスを相手側で作成できるようにすることです。

クラスが依存するモジュールやグローバル変数など、依存関係がある可能性があることを理解しています。これらもピクルス化の工程でまとめたいのですが、依存関係の自動検出については気にしていません。

4

3 に答える 3

6

を使用すると、(ほとんどの場合) Python モジュールのようdillに扱うことができます。__main__したがって、対話的に定義されたクラスなどをシリアライズできます。 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)
... 
>>> 

次に、インタープリターをシャットダウンし、test.pklTCP 経由でファイルを送信します。リモート マシンで、クラス インスタンスを取得できるようになりました。

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は、関数とクラスの依存関係を検出できるメソッドがあり、(ほとんどの場合) 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

したがって、それは「完璧」ではありません (または、期待どおりではない可能性があります)。ただし、動的に構築されたメソッドと依存関係のコードをシリアル化します。クラスの残りの部分は取得できませんが、この場合、クラスの残りの部分は必要ありません。

すべてを取得したい場合は、セッション全体をピクルするだけです。

>>> 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またはppftを使用できます。これにより、オブジェクトを 2 番目の 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ですが、代わりに (または同様に) リモート マシン名とポートを使用すると、リモート マシンに「簡単に」接続できます。

dillpathos、およびppftここで 入手してください: https://github.com/uqfoundation

于 2015-01-22T17:12:15.680 に答える
4

残念ながら、直接ではありません。ステートメントの文字列形式またはバイトコード形式を送信し、受信側classで を使用して「復元」できます。exec

于 2010-04-13T02:44:04.377 に答える
3

ドキュメントは、ピクルス化できるものとできないもの、およびその理由を説明するのに非常に優れています。

http://docs.python.org/library/pickle.html#what-c​​an-be-pickled-and-unpickled

基本的に、クラスまたはモジュールが unpickle されたときに名前でインポート可能であれば、今から unpickle するまでの間にクラス定義を変更する予定がない限り、動作するはずです。以下のクラス定義では、クラス名「Test」とメソッド名「mymethod」のみがピクルされます。クラス定義を pickle アウトしてから、attr が別の値になるように定義を変更すると、mymethod がまったく別の処理を実行すると、pickle は新しい定義を取得します。

class Test(object):
    attr = 5

    def mymethod(self, arg):
        return arg
于 2010-04-13T07:32:48.353 に答える