2012-01-02 13 views
3

私はCでPython拡張を作成しました。問題なく動作します。今私はそれでピクルスを使用したいと思います。ドキュメントから私は混乱しています。 「拡張子」のために、ここで示唆したように、私はテスト__reduce__機能を書いた:C++で書かれたPythonエクステンションにpickleを追加する

http://docs.python.org/library/pickle.html#the-pickle-protocol

を私が欠場すると「呼び出し可能オブジェクトは」あるべきものです。私はPyObject_Type(self)の結果を試しました。これは "呼び出し可能"であり、本質的には機能しますが、オブジェクトがunickledのときは__init__が呼び出されます。

クラスの初期化を避けて、__new__メソッドを呼び出す呼び出し可能オブジェクトを持つ標準的な方法はありますか?

+0

原則として、 '__init__'は呼び出されるべきではありません。それはpickleの好ましい方法です。 '__getinitargs__'を参照してください:" pickleされたクラスインスタンスがunpickleされているとき、その '__init __()'メソッドは通常は呼び出されません*。 '__getinitargs__'を実装していますか? –

+0

元気です。それは普通のクラスのためだけです。 –

答えて

2

__new__を呼び出し、タイプをメタクラスとして使用している場合は、__new__の結果がタイプのサブタイプである場合は、__init__が呼び出されます。別の言い方をすると、クラスFooがあるとしましょう。 PyObject_Type(self)の結果を呼び出す場合は、Foo()と同じです。これはFooを意味します。 __new__が呼び出され、戻り値がFooのサブタイプの場合は、__init__が呼び出されます。

Foo()を呼び出すと、実際にtype_call(typeobject.c内)が呼び出されます。これは、tp_newの後にtp_initが続くものです。オブジェクトの新しい機能(PyObject_Type(self)ではなくFoo_new()など)を直接提供する場合は、__init__を呼び出さずに__new__を呼び出して、探しているものを得ることができます。 (Fooを__new__の引数として提供することを忘れないでください)。

最後に質問にお答えするには、Foo.__new__(Foo, ...)に電話してください。あなたが探しているものを行うコードがいくつかあります。私はこのすべてを把握しようとしていたとき、余談として

class Foo(object): 
    def __new__(cls): 
     return super(Foo, cls).__new__(cls) 

    def __init__(self): 
     print "__init__" 

    def __reduce__(self): 
     return (Foo.__new__, (Foo,)) 

print "one" 
x = Foo()    # prints __init__ 

print "two" 
y = Foo.__new__(Foo) # does not print __init__ 

print "three" 
import pickle 
p = pickle.dumps(Foo) 
z = pickle.loads(p) # does not print __init__ 

は、私はほとんどすべてのケースで、私は、実際には、私のコードを実装し、__init__が呼ばれることを可能にすることを見出しました。私のエラーは、私が__reduce__タプルの3番目の引数に入るものを分離していないという事実に起因しています。 (__init__がそれを受け入れるならば)2番目の議論のために何も提供するのは完全にOKであり、__dict__を直接更新する3番目の議論のものを提供するだけです。モジュールとオブジェクトのディレクトリにあるcpythonのソースコードを見ると、__reduce__の実装がいくつも見られます。

+0

こんにちはNathan、ありがとうございます。何らかの理由でPythonで説明したことが、コンパイルされたC++拡張で定義されている型で起こっていなかったのです。 特に、 '__reduce__'出力の最初の項目は、 ' PyTuple_SetItem(res、0、PyObject_Type(self)); ' と書かれていますが、これは_pickle.loads(...)_、オブジェクト自体を呼び出すために、実際には '__new__'と' __init__'を実行します。 私は単純な解決策として、Pickleにプロトコル2を使用させるだけです。これは '__reduce__'関数を実装する必要はなく、' __getnewargs__'と通常の '__setstate__'と' __getstate__'を必要とします。 –

+0

'PyObject_Type(self)'を返すのではなく、self-> tp_newを使いたいのですが、それを試しましたか?それが動作しているか動作していないかを教えてください。もしそうなら、私は自分の投稿を更新します。そうでなければ、私が間違って書き込んだものを見つけ出すでしょう。 –

関連する問題