boost::python, returning new PyObject references

David Abrahams david.abrahams at rcn.com
Tue Jan 8 01:21:09 CET 2002


----- Original Message -----
From: "Barry Scott" <barry at scottb.demon.co.uk>


> PyCXX does 1 for all the reasons that Guido outlined.

Is the documentation out-of-date? It (cxx.sourceforge.net) says:

...
Class Object represents the most general kind of Python object. The rest of
the classes that represent Python objects inherit from it.

Object
    Type
    Int
    Float
    Long
    Sequence
        String
        Tuple
        List
    Mapping
        Dict
    Callable
...

> In PyCXX you call supportXXX functions to wire up Python object slots
> up to virtual functions of the Extension class.

This isn't about extension classes in Boost.Python, FWIW. We've got
extension classes completely handled. This is about how to write C++
functions that manipulate other (possibly arbitrary) Python objects. So, if
I write a C++ function which takes an arbitrary mapping as an argument, I
could use PyObject* and go through the regular Python 'C' API, but that
would be relatively unsafe and clumsy. I'd rather write something like:

    void f(python::mapping x);

I'd like to arrange it so that when mappings are constructed from PyObject*,
we check that the mapping concept is satisfied (throwing an exception
otherwise), and so that the public interface to mapping doesn't contain any
operations which are unsupported by the object.

> For example this is a fragment that creates an python extension object
> that acts as supports sequence, getattr, setattr and repr.
>
> class bemacs_buffer_data : public Py::PythonExtension<bemacs_buffer_data>
> {
> // static methods
> public:
> static void init_type()
> {
>         behaviors().name("bemacs_buffer");
>         behaviors().doc("bemacs buffer");
>         behaviors().supportGetattr();
>         behaviors().supportSetattr();
>         behaviors().supportRepr();
>   behaviors().supportSequenceType();
> }

In Boost.Python you just expose the functions you want with the appropriate
names, so to expose a std::vector<std::string> as a sequence of strings you
might have:

python::class_builder<std::vector<std::string> >
    vec_string(my_module, "vec_string");

vec_string.def(&std::vector<std::string> >::operator[], "__getitem__");

You don't need to otherwise declare that it's a sequence. Your module's
"vecstring" class now has a __getitem__ which accepts python Integers (and
other types convertible to int) and hands back Python Strings.

Actually this example needs an additional type cast to select the const
version of operator[] since vector's operator[] is overloaded, but I omitted
it for clarity.

> I took the view that to be a sequence type requires you to wire up all the
> slots that sequences typically use. I could have allowed each slot to be
wire
> independently, but it seems more useful to wire up all the sequence slots,
or
> all the mapping slots etc.

Unfortunately, there are places where the Python interpreter looks at the
slots and makes decisions based on what it sees are wired up, so I try hard
not to fill any slots that I'm not really implementing. Guido's doing the
same thing in the new type system.

-Dave





More information about the Cplusplus-sig mailing list