2016-05-17 15 views
0

短いバージョン:PyType_TypeをPython 3で使用して、PyClass_Newの代わりに使用する場合は、辞書を作成する前にクラスを作成する必要があります。ただし、PyMethod_Newでは、メソッドを作成する前にクラスを知っている必要があります。 Python 3の新しいクラスの辞書にメソッドを追加するにはどうすればよいですか?Python 3でC API経由で新しいクラスをメソッドで定義する方法は?

Python 2では、私はPyClass_Newで新しいクラスを定義するために使用されました。ここで私は方法helloと新しいクラスexample.MyClassを定義し、(パイソン2)最小限の実施例は、次のとおり

#include <Python.h> 
#include <stdio.h> 

PyObject * 
callback(PyObject *obj, PyObject *args) 
{ 
    printf("Hello world!\n"); 
    return Py_None; 
} 

int 
main(int argc, char *argv[]) 
{ 
    Py_SetProgramName(argv[0]); 
    Py_Initialize(); 
    PyObject *module = PyModule_New("example"); 
    PyDict_SetItemString(PyImport_GetModuleDict(), "example", module); 
    PyObject *dict = PyDict_New(); 
    PyObject *classname = PyBytes_FromString("MyClass"); 
    PyObject *class = PyClass_New(PyTuple_New(0), dict, classname); 
    PyMethodDef method_def; 
    method_def.ml_name = "method_closure"; 
    method_def.ml_meth = callback; 
    method_def.ml_flags = 1; 
    method_def.ml_doc = "Method closure"; 
    PyObject *closure = PyCFunction_New(&method_def, NULL); 
    PyObject *method = PyMethod_New(closure, NULL, class); 
    PyDict_SetItemString(dict, "hello", method); 
    PyModule_AddObject(module, "MyClass", class); 
    PyRun_SimpleString("from example import MyClass\nMyClass().hello()"); 
    Py_Finalize(); 
    return 0; 
} 

PyClass_NewはPythonの3 CのAPIから除去しました。 What is the PyClass_New equivalent in Python 3?

しかし、それは辞書PyObject_CallFunctionObjArgsは、新しいクラスの作成中にコピーされ、最後の引数に取ることと思わ:確かに、私はPyObject_CallFunctionObjArgsは、次の質問の答えには例えば、代替として使用することができることを読んでPyObject_CallFunctionObjArgsを呼び出す前にdictに設定されているフィールドは、クラスのインスタンスで使用できますが、呼び出し後に設定されたフィールドは使用できません。 これは、メソッドを作成する前にクラスを知っていなければならないため、クラスを作成する前にdictにメソッドを追加する必要があるため、上記のようにPyMethod_Newを使用できなくなります。

この依存ループは、PyInstanceMethod_newを使用することで解決できます。後者はクラスの参照を取らないためです。私はこうして次の作業例を得ました(Python 3の場合は、mainのコードを与え、プリアンブルとコールバックは最初の例と同じです)。

int 
main(int argc, char *argv[]) 
{ 
    wchar_t progname[FILENAME_MAX + 1]; 
    mbstowcs(progname, argv[0], strlen(argv[0]) + 1); 
    Py_SetProgramName(progname); 
    Py_Initialize(); 
    PyObject *module = PyModule_New("example"); 
    PyDict_SetItemString(PyImport_GetModuleDict(), "example", module); 
    PyObject *dict = PyDict_New(); 
    PyMethodDef method_def; 
    method_def.ml_name = "method_closure"; 
    method_def.ml_meth = callback; 
    method_def.ml_flags = 1; 
    method_def.ml_doc = "Method closure"; 
    PyObject *closure = PyCFunction_New(&method_def, NULL); 
    PyObject *method = PyInstanceMethod_New(closure); 
    PyDict_SetItemString(dict, "hello", method); 
    PyObject *classname = PyUnicode_FromString("MyClass"); 
    PyObject *class = PyObject_CallFunctionObjArgs(
     (PyObject *) &PyType_Type, classname, PyTuple_New(0), dict); 
    PyModule_AddObject(module, "MyClass", class); 
    PyRun_SimpleString("from example import MyClass\nMyClass().hello()"); 
    Py_Finalize(); 
    return 0; 
} 

しかし、私は私がPyMethod_newを使用して、Pythonの2バージョンに近いソリューションを書くために達成することができるかどうかを疑問に思う:動的に新しいメソッドを追加するために、その作成後にクラスを変更することが可能ですが、私ドンそれをどうやって行うのか理解していない。

答えて

0

実際にタイプを作成するためにC APIを使用していません。

C APIで型を定義する通常の方法は、オブジェクトのレイアウトをC構造体として定義し、PyTypeObjecttp_*というフィールドを定義してそのプロパティを定義することです。これはExtending and Embedding the Python Interpreter: Defining New Typesの下に文書化されています。 PyObject_CallFunctionObjArgsは関与していません。

PyObject_CallFunctionObjArgsPyType_Typeとすることは、typeをPythonで手作業で呼び出すことによって型を作成することに似ています。この場合、型のdictはメソッドオブジェクトを含むべきではありません。あなたがPythonでそれをやっていたのと同じように、辞書にはPythonの関数オブジェクトが含まれ、メソッドオブジェクトは属性アクセスで動的に作成されます。

関連する問題