[capi-sig] Announcing project PyBindGen
Gustavo Carneiro
gjcarneiro at gmail.com
Tue Sep 25 14:21:34 CEST 2007
On 25/09/2007, Stefan Behnel <python_capi at behnel.de> wrote:
>
>
> Gustavo Carneiro wrote:
> > On 25/09/2007, *Stefan Behnel* <python_capi at behnel.de
> > <mailto:python_capi at behnel.de>> wrote:
> >
> > I don't understand what "exact API mapping" means.
>
> What I meant was: is the C(++) API mapped directly to Python or can you
> write
> abstraction code in between?
Generally it requires a direct mapping. Why would you want to write code in
the middle? Although recently I added support for adding "user functions"
to make them appear as methods of objects.
Anyway that's not the point. The PyBindGen design is not set in stone...
> But yes, so far you have to write all this by hand. Although would love
> > to have automatic header file scanning, one day... unfortunately I have
> > not had enough time for that, and would rather focus on the code
> > generation for now. Lots of neat things could be done later on top of
> > the pybindgen python module interface...
>
> But that's what most wrapper generators are there for: move the work from
> the
> developer into a generator. If you have to write code for every
> function/method/class you wrap, I think you're better of with
> Pyrex/Cython, as
> Pyrex code is readable and meaningful Python, not just a wrapper writer
> script.
Come on, I wouldn't say this interface is unreadable. It's stuff like this:
mod = Module('foo')
Foo = CppClass('Foo', automatic_type_narrowing=True)
mod.add_class(Foo)
Foo.add_static_attribute(ReturnValue.new('int'), 'instance_count')
Foo.add_constructor(
CppConstructor([Parameter.new('std::string', 'datum')]))
Foo.add_constructor(CppConstructor([]))
Foo.add_method(CppMethod(ReturnValue.new('std::string'), 'get_datum',
[]))
Not that hard to write this, is it?
> I don't like having to learn a new language for this. Just like
> > Boost.Python users are comfortable with C++ and avoid having to learn a
> > new language, PyBindGen users are comfortable with Python and don't have
> > to learn a new language.
>
> Pyrex is *almost* Python, no new language to learn. And Cython is even
> closer,
> as it features a couple of Python 2.5 and Python 3k features.
>
>
> > Besides, pyrex/cython C++ support is poor or nonexistent. Although I
> > acknowledge that if you wrap pure C libraries then this point is moot.
>
> There are a couple of patches that improve the support. Admittedly, Pyrex
> does
> not target C++ libraries, so OO support is mostly missing. But nothing
> keeps
> you from implementing an object interface against C++ classes. I bet the
> Cython project would be happy to include it.
>
>
> > Finally, have you ever looked at the code generated by pyrex?
>
> Yes, definitely, it's pretty readable, well optimised (with Cython, that
> is)
> and straight forward (ok, loops are ugly and over-optimised - but *very*
> fast). And I totally like the Cython feature of keeping the surrounding
> Cython
> code inside a C comment. That way, you immediately know what you are
> looking at.
For instance, I don't find this very readable:
static PyObject *__pyx_f_4spam_4Spam_get_amount(PyObject *__pyx_v_self,
PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
static PyObject *__pyx_f_4spam_4Spam_get_amount(PyObject *__pyx_v_self,
PyObject *__pyx_args, PyObject *__pyx_kwds) {
PyObject *__pyx_r;
PyObject *__pyx_1 = 0;
static char *__pyx_argnames[] = {0};
if (unlikely(!PyArg_ParseTupleAndKeywords(__pyx_args, __pyx_kwds, "",
__pyx_argnames))) return 0;
Py_INCREF(__pyx_v_self);
/* "/Users/robert/sage/pyrex/cython-0.9.6.3/Demos/spam.pyx":16
*
* def get_amount(self):
* return self.amount # <<<<<<<<<<<<<<
*
* def set_amount(self, new_amount):
*/
__pyx_1 = PyInt_FromLong(((struct __pyx_obj_4spam_Spam
*)__pyx_v_self)->amount); if (unlikely(!__pyx_1)) {__pyx_filename =
__pyx_f[0]; __pyx_lineno = 16; goto __pyx_L1;}
__pyx_r = __pyx_1;
__pyx_1 = 0;
goto __pyx_L0;
__pyx_r = Py_None; Py_INCREF(Py_None);
goto __pyx_L0;
__pyx_L1:;
Py_XDECREF(__pyx_1);
__Pyx_AddTraceback("spam.Spam.get_amount");
__pyx_r = 0;
__pyx_L0:;
Py_DECREF(__pyx_v_self);
return __pyx_r;
}
Compared with this code generated by pybindgen:
static PyObject *
_wrap_fooinvoke_some_object_get_prefix()
{
PyObject *py_retval;
std::string retval;
retval = invoke_some_object_get_prefix();
py_retval = Py_BuildValue("s#", retval.c_str(), retval.size());
return py_retval;
}
Pybindgen generated code is almost as clean as the code you would write by
hand. To me that counts a lot. I know some people don't care what happens
underneath the tools they use as long as it works. I am not that kind of
person.
--
Gustavo J. A. M. Carneiro
INESC Porto, Telecommunications and Multimedia Unit
"The universe is always one step beyond logic." -- Frank Herbert
More information about the capi-sig
mailing list