[capi-sig] Creating type object dynamically in run-time

Stefan Behnel python_capi at behnel.de
Thu May 10 18:39:44 CEST 2012


Mateusz Loskot, 10.05.2012 18:17:
> On 10 May 2012 14:55, Mateusz Loskot wrote:
>> On 10 May 2012 14:01, Stefan Behnel wrote:
>>> You can execute any Python code from your C code. Look for the
>>> PyRun_*() functions.
>>
>> Do you mean something similar to this approach?
>>
>>  /* dynamically generated lengthy class definition */
>> const char* c = "class A(object): pass";
>>
>> PyObject* class_a = PyRun_StringFlags(c, ...);
>> PyObject_SetAttrString(module, "A", class_a)
> 
> The pseudo-code above is incorrect.
> I have come up with the following example of dynamically
> generating new Python class, indirectly through script using class keyword.
> Such dynamically created class is added to module dictionary:
> 
> /* error checks removed for brevity */
> 
> static PyModuleDef embmodule = { ... };
> 
> PyInit_emb(void)
> {
>     PyObject* m = PyModule_Create(&embmodule);
>     PyObject* d = PyModule_GetDict(m);
> 
>     /* Required to allow 'class' use in context of module which is
>        not yet complete and ready. Otherwise, error is thrown:
>        ImportError: __build_class__ not found
>     */
>     PyObject* builtins = PyEval_GetBuiltins();
>     PyDict_SetItemString(d, "__builtins__", builtins);
> 
>     /* Python class is dynamically generated */
>     const char* c = "class A(object):\n\tpass"; /* sample class */
> 
>     /* Create object for A class, automatically added to the module
> dictionary as noddy.A */
>     PyRun_StringFlags(c, Py_file_input, d, d, NULL);

You want to take the result here, if only to decref it.

What you'd do next is to initialise your types in the module (or let
CPython do it for you through the inittab) and then let the Python classes
inherit from them, stick C methods into them, etc.


>     return m;
> }
> 
> This approach works well.
> If anyone noticed a problem or there is better way to do the same,
> please let me know.

Looks ok to me.

Here's the equivalent code in Cython:

    class A(object): pass

(except that it executes faster because it doesn't run through the Python
parser and interpreter at runtime, but I don't think that matters much at
module init time).

Stefan


More information about the capi-sig mailing list