A new Python header

Kirk McDonald kirklin.mcdonald at gmail.com
Tue Jun 20 16:26:20 PDT 2006


In wrapping Python, I have had cause to update David Rushby's version of 
the Python API header for D.

Aside from some bug fixes, one thing I've been trying to do is remove 
the need to call _loadPythonSupport() at the start of every module. This 
is not much of a burden with the wrapper I'm writing (it can simply call 
it in the module_init function), but I have an idea which I think would 
work better. The trouble is, it seems to cause Python to crash, which 
always seems to put a damper on things.

The _loadPythonSupport function just loads a whole mess of singleton 
objects. Py_None, Py_True, Py_False, all of the type objects, and all of 
the exception types, and some others. Rather than load all of these 
things when the module is loaded (as a given module will only need to
use a few of them), I am trying to load them lazily:

(Excuse the formatting, I didn't pay close attention to width when I 
wrote it.) :-)

private {

PyObject* m_Py_None;
PyObject* m_Py_True;
// ... and so on for all of the singletons

PyObject* m_builtins, m_types, m_weakref;

// Note the new function template syntax. Ohh, ahh.
typeof(Ptr) lazy_sys(alias Ptr, char[] name) () {
     if (Ptr is null) {
         PyObject* sys_modules = PyImport_GetModuleDict();
         Ptr = PyDict_GetItemString(sys_modules, name ~ \0);
         Py_DECREF(sys_modules);
         assert (Ptr !is null,
             "python.d couldn't load " ~ name ~ " attribute!");
     }
     return Ptr;
}

alias lazy_sys!(m_builtins, "__builtin__") builtins;
alias lazy_sys!(m_types, "types") types;
alias lazy_sys!(m_weakref, "weakref") weakref;

typeof(Ptr) lazy_load(alias from, alias Ptr, char[] name) () {
     if (Ptr is null) {
         Ptr = cast(typeof(Ptr)) PyObject_GetAttrString(from(),
             name ~ \0);
         assert (Ptr !is null,
             "python.d couldn't load " ~ name ~ " attribute!");
     }
     return Ptr;
}

} /* end private */

alias lazy_load!(builtins, m_Py_None, "None") Py_None;
alias lazy_load!(builtins, m_Py_True, "True") Py_True;
// ... and so on for all of the singletons

The loading code is based on David Rushby's.

Note that, though these are functions, you don't actually need to call 
them. Viz. you don't need to say "Py_None()", just "Py_None", as D seems 
to treat them like properties, or something. I'm still not totally clear 
on why that works, I only know that it does. (The "def" template in my 
Python wrapper makes use of the same oddity.)

Thus, the singletons are loaded the first time they are needed, and only 
the first time they are needed. There is no need to call Py_DECREF on 
these references in (say) a static destructor, as Python cannot "unload" 
a module; and besides, they cannot be deallocated by Python anyway.

This does, in fact, work, except for the wee problem that Python, once 
it has loaded a module compiled with this header, crashes horribly when 
you try to quit it. This makes me suspect something very wrong is 
happening when Python tries to unload the module. I'm not sure precisely 
what I did here that would cause this, however, and so I throw this out 
for ideas.

-Kirk McDonald



More information about the Digitalmars-d mailing list