2016-10-10 2 views
0

Wie erstelle ich mit der Python C/API eine normale Python-Klasse mit dem normalen Python-Mechanismus zur Klassenerstellung (d. H. Kein Erweiterungstyp)?Python C/API: Wie erstelle ich eine normale Klasse

Mit anderen Worten, was ist der Python C/API-Äquivalent (in dem Sinne, dass es genau das gleiche in allen Fällen des Fall ist) eine Aussage

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

Antwort

1

Ich bin nicht sicher, was du meinst durch die „normale Python-Klasse-creation-Mechanismus“, aber ...

es gibt eine Dokumentation Seite widmet sich: https://docs.python.org/3/extending/newtypes.html - es einen neuen Typ in einem Erweiterungsmodul erzeugt, das auf die Schaffung einer neuen class in Python entspricht Code.

Die minimale Beispiel präsentiert ist:

#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

Das ist genau das, was ich nicht wollen. Ich möchte keinen Erweiterungstyp, sondern nur eine zur Laufzeit erstellte Python-Klasse. –

+0

@JeroenDemeyer: Ihre Fragen sagen "Python C/API entspricht einer Aussage wie", so habe ich das verstanden. Bitte überlege, deine Frage umzuformulieren. –

+0

Ich meine "Äquivalent" im wörtlichsten Sinne. Ich meine nicht "ähnlich", ich meine "genau das Gleiche". –

4

In Python können Sie eine Klasse programmatisch erstellen, indem Sie die type integrierte Funktion aufrufen. Siehe zum Beispiel this answer.

Dies erfordert drei Argumente: einen Namen, ein Tupel von Basen und ein Wörterbuch.

Sie können die Python type im CAPI als PyType_Type erhalten. Sie brauchen dann nur es one of the standard methods for calling PyObject* callables mit nennen:

// 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); 

(Beachten Sie, dass Sie &PyType_Type zu tun haben - die Dokumentation impliziert, dass es ein PyObject* ist, aber es ist nicht!)

+0

Danke, das scheint zu funktionieren. Ich frage mich zwar, ob "Klasse Abgeleitet (Basis): bestanden" wirklich 100% äquivalent zu "Abgeleitet = Typ (" Abgeleitet ", (Basis,), {})" ist, wenn Metaklassen beteiligt sind. –

+0

Ich glaube, wenn Metaklassen beteiligt sind, sollten Sie 'Derived = metaclass (" Derived ", (Base,), {})' nennen. Dies ist jedoch etwas jenseits dessen, was ich eigentlich sicher bin ... – DavidW

+0

Nur als eine zusätzliche Sache - haben Sie diese https://mail.python.org/pipermail/python-dev/2009-July/090921.html gesehen ? Es scheint einen zweiten Weg zu geben, wie man 'PyTypeObject' selbst zuordnen kann (aber niemand scheint es zu mögen ...) – DavidW

Verwandte Themen