Python instance method in C

后端 未结 3 2072
臣服心动
臣服心动 2021-01-06 18:14

Consider the following Python (3.x) code:

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

How to write the same functionalit

相关标签:
3条回答
  • 2021-01-06 18:36

    You can't! C does not have "classes", it only has structs. And a struct cannot have code (methods or functions).

    You can, however, fake it with function pointers:

    /* 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();
    
    0 讨论(0)
  • 2021-01-06 18:37

    Here's a simple class (adapted from http://nedbatchelder.com/text/whirlext.html for 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 讨论(0)
  • 2021-01-06 18:43

    I suggest you start from the example source code here -- it's part of Python 3's sources, and it exists specifically to show you, by example, how to perform what you require (and a few other things besides) -- use the C API to create a module, make a new type in that module, endow that type with methods and attributes. That's basically the first part of the source, culminating in the definition of Xxo_Type -- then you get examples of how to define various kinds of functions, some other types you may not care about, and finally the module object proper and its initialization (you can skip most of that of course, though not the module object and the parts of its initialization that lead up to the definition of the type of interest;-).

    Most of the questions you might have while studying and adapting that source to your specific needs have good answers in the docs, especially in the section on "Object Implementation Support" -- but of course you can always open a new question here (one per issue would be best -- a "question" with many actual questions is always a bother!-) showing exactly what you're doing, what you were expecting as a result, and what you are seeing instead -- and you'll get answers which tend to include some pretty useful ones;-).

    0 讨论(0)
提交回复
热议问题