[C++-sig] Interface design.

Nicodemus nicodemus at globalite.com.br
Tue Apr 22 18:24:44 CEST 2003


tALSit de CoD wrote:

> At 10:27 22/04/2003 -0400, you wrote:
>
>> tALSit de CoD <talsit at talsit.org> writes:
>>
>> Or you can actually break your extension module into separate
>> extension modules.  It's a little-known and underutilized feature of
>> Boost.Python that component-based development is supported.
>
>
> But can you have nested modules? As in:
>
> BOOST_PYTHON_MODULE (kikura) {
>         BOOST_PYTHON_MODULE (kikuraCore) {
>                 ... stuff ...
>         }
>         BOOST_PYTHON_MODULE (kikuraNode) {
>                 ... stuff ...
>         }
> }
>
> Or would you need something like so:
>
> BOOST_PYTHON_MODULE (kikuraCore) {
>         ... stuff ...
> }
> BOOST_PYTHON_MODULE (kikuraNode) {
>         ... stuff ...
> }
>
> In this case (or both really), how would you import the modules from 
> python? I'm not too sure how python looks for dynamic libs, but would 
> you have to put each module in a separate dynamic library, and then 
> call from python:
>
> import kikuraCore
> import kikuraNode
>
> ?
>
> For now, I'll be using the "unpreferred" approach to splitting up the 
> thingy, as long as it works.
>
> Cheers!


Hi!

Suppose you want to have a top level package in python named kikura, 
with two sub-modules, core and node, so that a user uses your package 
like this:

    import kikura.core
    import kikura.node
    kikura.core.Foo()


You can acomplish this generating the two sub-modules (core and node) 
using Boost.Python, like any other module:

    // file core.cpp
    BOOST_PYTHON_MODULE(core)
    {
       ...
    }

    // file node.cpp
    BOOST_PYTHON_MODULE(node)
    {
       ...
    }

    And creating the following directory structure:

    /kikura
        __init__.py 
        core.pyd
        node.pyd


And that's it (the file __init__.py indicates that the directory is a 
package. It can be empty, but it can be useful to provide a more 
friendly interface for your users. See below).

I suggest that you name your bindings _core and _node, thought, and make 
the sub-modules *python* modules which import the funcionality of the 
bindings, like so:

    /kikura
        __init__.py
        /core
            __init__.py
            _core.pyd
        /node
            __init__.py
            _node.pyd


with /kikura/core/__init__.py contains the statement "from _core import 
*". The same for the node package. Why do it like this? Well, because 
then you can easily implement some things in python in a way that is 
transparent for the user (I am assuming here that you're developing this 
library). Suppose you want to add a new utility function into the core 
package, made in python. You just create a file "foo.py" and put it 
inside /kikura/core, and add this line to its __init__.py:

    from foo import util_function, other_function


and your users will access it like so:

    import kikura.core
    kikura.core.util_function(10)


Back to the compilation time issue, notice that you don't have to write 
all class_ declarations inside the BOOST_PYTHON_MODULE macro directly, 
you can split them in any number of files you like. For example:

    // file Foo.cpp
    #include <kikura/Foo.h>
    void export_foo()
    {
        class_<Foo>()...
    }

    // file Bar.cpp
    #include <kikura/Bar.h>
    void export_bar()
    {
        class_<Bar>()...
    }

    // file core.cpp
    void export_foo();
    void export_bar();
    BOOST_PYTHON_MODULE(core)
    {
        export_foo();
        export_bar();
    }


This will take longer to compile than a single file (because the 
Boost.Python headers must be compiled for each cpp), but if your 
developing the library this is a big help, because a change in a header 
doesn't mean the entire bindings will have to be recompiled.

Hope that helps,
Nicodemus.







More information about the Cplusplus-sig mailing list