2009-12-23 6 views
2

Considérons le code Python (3.x) suivante:méthode d'instance Python en C

class Foo(object): 
    def bar(self): 
     pass 
foo = Foo() 

Comment écrire les mêmes fonctionnalités en C?

Je veux dire, comment puis-je créer un objet avec une méthode en C? Et puis créer une instance de celui-ci?

Édition: Oh, désolé! Je voulais dire la même fonctionnalité via l'API Python C. Comment créer une méthode Python via son API C? Quelque chose comme:

PyObject *Foo = ?????; 
PyMethod??? *bar = ????; 
+0

Les structures peuvent contenir des pointeurs vers des fonctions. Une structure est presque comme une classe. –

+2

Je pense que la plupart des gens interprètent mal la question (ou peut-être que je suis), vous pourriez vouloir l'éclaircir. Je comprends, la question est de savoir comment utiliser l'API C Python pour créer une classe python, et une instance de celle-ci. Je n'ai jamais utilisé l'API C, mais je suis certain que vous ne pouvez créer que des fonctions, puis écrire la classe en Python pour accéder à ces fonctions. –

+0

Oui, exactement! Je m'excuse pour la confusion! – EcirH

Répondre

2

est ici une simple classe (adapté de http://nedbatchelder.com/text/whirlext.html 3.x):

#include "Python.h" 
#include "structmember.h" 

// The CountDict type. 

typedef struct { 
    PyObject_HEAD 
    PyObject * dict; 
    int count; 
} CountDict; 

static int 
CountDict_init(CountDict *self, PyObject *args, PyObject *kwds) 
{ 
    self->dict = PyDict_New(); 
    self->count = 0; 
    return 0; 
} 

static void 
CountDict_dealloc(CountDict *self) 
{ 
    Py_XDECREF(self->dict); 
    self->ob_type->tp_free((PyObject*)self); 
} 

static PyObject * 
CountDict_set(CountDict *self, PyObject *args) 
{ 
    const char *key; 
    PyObject *value; 

    if (!PyArg_ParseTuple(args, "sO:set", &key, &value)) { 
     return NULL; 
    } 

    if (PyDict_SetItemString(self->dict, key, value) < 0) { 
     return NULL; 
    } 

    self->count++; 

    return Py_BuildValue("i", self->count); 
} 

static PyMemberDef 
CountDict_members[] = { 
    { "dict", T_OBJECT, offsetof(CountDict, dict), 0, 
       "The dictionary of values collected so far." }, 

    { "count", T_INT, offsetof(CountDict, count), 0, 
       "The number of times set() has been called." }, 

    { NULL } 
}; 

static PyMethodDef 
CountDict_methods[] = { 
    { "set", (PyCFunction) CountDict_set, METH_VARARGS, 
       "Set a key and increment the count." }, 
    // typically there would be more here... 

    { NULL } 
}; 

static PyTypeObject 
CountDictType = { 
    PyObject_HEAD_INIT(NULL) 
    0,       /* ob_size */ 
    "CountDict",    /* tp_name */ 
    sizeof(CountDict),   /* tp_basicsize */ 
    0,       /* tp_itemsize */ 
    (destructor)CountDict_dealloc, /* tp_dealloc */ 
    0,       /* tp_print */ 
    0,       /* tp_getattr */ 
    0,       /* tp_setattr */ 
    0,       /* tp_compare */ 
    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 | Py_TPFLAGS_BASETYPE, /* tp_flags*/ 
    "CountDict object",  /* tp_doc */ 
    0,       /* tp_traverse */ 
    0,       /* tp_clear */ 
    0,       /* tp_richcompare */ 
    0,       /* tp_weaklistoffset */ 
    0,       /* tp_iter */ 
    0,       /* tp_iternext */ 
    CountDict_methods,   /* tp_methods */ 
    CountDict_members,   /* tp_members */ 
    0,       /* tp_getset */ 
    0,       /* tp_base */ 
    0,       /* tp_dict */ 
    0,       /* tp_descr_get */ 
    0,       /* tp_descr_set */ 
    0,       /* tp_dictoffset */ 
    (initproc)CountDict_init, /* tp_init */ 
    0,       /* tp_alloc */ 
    0,       /* tp_new */ 
}; 

// Module definition 

static PyModuleDef 
moduledef = { 
    PyModuleDef_HEAD_INIT, 
    "countdict", 
    MODULE_DOC, 
    -1, 
    NULL,  /* methods */ 
    NULL, 
    NULL,  /* traverse */ 
    NULL,  /* clear */ 
    NULL 
}; 


PyObject * 
PyInit_countdict(void) 
{ 
    PyObject * mod = PyModule_Create(&moduledef); 
    if (mod == NULL) { 
     return NULL; 
    } 

    CountDictType.tp_new = PyType_GenericNew; 
    if (PyType_Ready(&CountDictType) < 0) { 
     Py_DECREF(mod); 
     return NULL; 
    } 

    Py_INCREF(&CountDictType); 
    PyModule_AddObject(mod, "CountDict", (PyObject *)&CountDictType); 

    return mod; 
} 
+0

Ai-je vraiment besoin de créer un nouveau type pour créer une méthode d'instance simple? Je pensais que c'est beaucoup plus simple .... – EcirH

+0

Je ne connais pas de moyen de créer une méthode d'instance sans une instance, et vous avez besoin d'une classe pour créer une instance. –

+0

La création de types semble assez compliquée. Je pensais que créer une instance de classe prédéfinie "objet" serait beaucoup plus simple. Mais peut-être est-ce le cas dans les types Py3k sont la même chose que dans une classe? – EcirH

3

Vous ne pouvez pas! C n'a pas de "classes", il n'a que struct s. Et un struct ne peut pas avoir de code (méthodes ou fonctions).

Vous pouvez, cependant faux avec des pointeurs de fonction:

/* struct object has 1 member, namely a pointer to a function */ 
struct object { 
    int (*class)(void); 
}; 

/* create a variable of type `struct object` and call it `new` */ 
struct object new; 
/* make its `class` member point to the `rand()` function */ 
new.class = rand; 

/* now call the "object method" */ 
new.class(); 
2

Je vous suggère de commencer par l'exemple code source here - il fait partie des sources de Python 3, et il existe spécifiquement pour vous montrer, par exemple, comment effectuer ce dont vous avez besoin (et quelques autres choses en plus) - utiliser l'API C pour créer un module, faire un nouveau type dans ce module, doter ce type avec m éthodes et attributs. C'est essentiellement la première partie de la source, aboutissant à la définition de Xxo_Type - alors vous obtenez des exemples de la façon de définir différents types de fonctions, d'autres types qui ne vous intéressent pas, et enfin l'objet module proprement dit et son initialisation (vous peut sauter la plupart de cela bien sûr, mais pas l'objet module et les parties de son initialisation qui conduisent à la définition du type d'intérêt ;-).

La plupart des questions que vous pourriez avoir en étudiant et adaptant cette source à vos besoins spécifiques ont de bonnes réponses dans the docs, en particulier dans le section sur "Object Implementation Support" - mais bien sûr vous pouvez toujours ouvrir une nouvelle question ici montrant exactement ce que vous faites, ce que vous attendiez en conséquence, et ce que vous voyez à la place (! un par question serait préférable - - une « question » avec beaucoup de réelles des questions est toujours pris la peine) - et vous obtiendrez des réponses qui ont tendance à inclure des réponses très utiles ;-).

+0

Ce lien concerne la création de nouveaux types, je pensais qu'il était possible de créer simplement un simple PyObject et d'ajouter en quelque sorte un objet appelable (méthode). Mais peut-être que je ne comprends pas complètement - dans Python 3, les types et les objets sont-ils la même chose? – EcirH

+0

@Ecirh, non: tous les types sont des objets, mais tous les objets ne sont pas des types. Vous pouvez ajouter des attributs appelables à certains objets qui ne sont pas des types (tels que des modules), mais ces attributs appelables ne seront pas des "méthodes" - ils seront généralement des fonctions simples. Si ce que vous voulez, c'est créer un nouvel objet module et lui ajouter une fonction, merci de le dire plutôt que de mentionner spécifiquement les "méthodes d'instance" !!! –

+0

Désolé, je suis confus. Vous avez raison, je ne veux pas précisément des "méthodes d'instance", je ne savais pas qu'il était possible de satisfaire 'writer = PyObject_GetAttrString (f," write ");' par quelque chose d'autre que "instance method". – EcirH