2016-10-10 2 views
0

Использование Python C/API, как создать обычный класс Python с использованием обычного механизма создания класса Python (т. Е .: не тип расширения)?Python C/API: как создать нормальный класс

Другими словами, что является/API эквивалент Python C (в том смысле, что он делает точно одинакова во всех случаях) оператора

class X(bases): 
    ...some methods/attributes here... 

ответ

1

Я не уверен, что вы имеете в виду «нормальный механизм создания класса Python», но ...

Для этого есть страница документации: https://docs.python.org/3/extending/newtypes.html - он создает новый тип в модуле расширения, что эквивалентно созданию нового class в Python код.

Минимальный пример представлен там:

#include <Python.h> 

typedef struct { 
    PyObject_HEAD 
    /* Type-specific fields go here. */ 
} noddy_NoddyObject; 

static PyTypeObject noddy_NoddyType = { 
    PyVarObject_HEAD_INIT(NULL, 0) 
    "noddy.Noddy",    /* tp_name */ 
    sizeof(noddy_NoddyObject), /* tp_basicsize */ 
    0,       /* tp_itemsize */ 
    0,       /* tp_dealloc */ 
    0,       /* tp_print */ 
    0,       /* tp_getattr */ 
    0,       /* tp_setattr */ 
    0,       /* tp_reserved */ 
    0,       /* tp_repr */ 
    0,       /* tp_as_number */ 
    0,       /* tp_as_sequence */ 
    0,       /* tp_as_mapping */ 
    0,       /* tp_hash */ 
    0,       /* tp_call */ 
    0,       /* tp_str */ 
    0,       /* tp_getattro */ 
    0,       /* tp_setattro */ 
    0,       /* tp_as_buffer */ 
    Py_TPFLAGS_DEFAULT,  /* tp_flags */ 
    "Noddy objects",   /* tp_doc */ 
}; 

static PyModuleDef noddymodule = { 
    PyModuleDef_HEAD_INIT, 
    "noddy", 
    "Example module that creates an extension type.", 
    -1, 
    NULL, NULL, NULL, NULL, NULL 
}; 

PyMODINIT_FUNC 
PyInit_noddy(void) 
{ 
    PyObject* m; 

    noddy_NoddyType.tp_new = PyType_GenericNew; 
    if (PyType_Ready(&noddy_NoddyType) < 0) 
     return NULL; 

    m = PyModule_Create(&noddymodule); 
    if (m == NULL) 
     return NULL; 

    Py_INCREF(&noddy_NoddyType); 
    PyModule_AddObject(m, "Noddy", (PyObject *)&noddy_NoddyType); 
    return m; 
} 
+0

Это именно то, что я НЕ хотеть. Я не хочу тип расширения, но только класс Python, созданный во время выполнения. –

+0

@JeroenDemeyer: В ваших вопросах говорится: «Python C/API эквивалент выражения вроде», так что это то, что я понял. Пожалуйста, подумайте о том, чтобы перефразировать ваш вопрос, чтобы быть более четким. –

+0

Я имею в виду «эквивалент» в самом буквальном смысле слова. Я не имею в виду «похожие», я действительно имею в виду «точно то же самое». –

4

В Python вы можете получить программно создать класс, вызвав type встроенную функцию. См. Например, this answer.

Это принимает три аргумента: имя, кортеж баз и словарь.

Вы можете получить Python type в C api как PyType_Type. После этого нужно просто вызвать его с помощью one of the standard methods for calling PyObject* callables:

// make a tuple of your bases 
PyObject* bases = PyTuple_Pack(0); // assume no bases 
// make a dictionary of member functions, etc 
PyObject* dict = PyDict_New(); // empty for the sake of example 
PyObject* my_new_class = PyObject_CallFunction(&PyType_Type,"sOO", 
              "X", // class name 
              bases, 
              dict); 
// check if null 

// decref bases and dict 
Py_CLEAR(bases); 
Py_CLEAR(dict); 

(Обратите внимание, что вы должны сделать &PyType_Type - документация подразумевает, что это PyObject*, но это не так!)

+0

Спасибо, это похоже на работу. Хотя мне интересно, «класс Derived (Base): pass» действительно на 100% эквивалентен «Derived = type (« Derived », (Base,), {})», если задействованы метаклассы. –

+0

Я считаю, что если метаклассы задействованы, вы должны вызвать 'Derived = metaclass (« Производные », (Base,), {})'. Тем не менее, это немного превышает то, что я на самом деле уверен ... – DavidW

+0

Так же, как дополнительная вещь - вы видели этот https://mail.python.org/pipermail/python-dev/2009-July/090921.html ? Существует второй способ сделать это с помощью выделения «PyTypeObject» (но кому-то, похоже, это нравится ...) – DavidW

Смежные вопросы