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

Mateusz Loskot mateusz at loskot.net
Thu May 10 19:13:14 CEST 2012


On 10 May 2012 17:39, Stefan Behnel <python_capi at behnel.de> wrote:
> 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 emb.A */
>>     PyRun_StringFlags(c, Py_file_input, d, d, NULL);
>
> You want to take the result here, if only to decref it.

Right, I missed it out from the example.

> What you'd do next is to initialise your types in the module (or let
> CPython do it for you through the inittab)

I'm not sure I completely understand it.
I assume that executing these two lines,
in context of the module:

const char* c = "class A(object):\n\tpass";
PyRun_StringFlags(c, Py_file_input, d, d, NULL);

creates complete and initialised A class within this module.
Doesn't it?

> and then let the Python classes
> inherit from them, stick C methods into them, etc.

Right.

Thanks for the patience :)

>> 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.

Great!

> 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).

It looks really helpful and simple, I'll remember,
and chances are I will use it in next project.

Best regards,
-- 
Mateusz Loskot, http://mateusz.loskot.net


More information about the capi-sig mailing list