#

# Exporting Classes

Now let's expose a C++ class to Python:

>     #include <iostream>
>     #include <string>

>     namespace { // Avoid cluttering the global namespace.

>       // A friendly class.
>       class hello
>       {
>         public:
>           hello(const std::string& country) { this->country = country; }
>           std::string greet() const { return "Hello from " + country; }
>         private:
>           std::string country;
>       };

>       // A function taking a hello object as an argument.
>       std::string invite(const hello& w) {
>         return w.greet() + "! Please come soon!";
>       }
>     }

To expose the class, we use a `class_builder` in addition to the `module_builder` from the previous example. Class member functions are exposed by using the `def()` member function on the `class_builder`:

>     #include <boost/python/class_builder.hpp>
>     namespace python = boost::python;

>     BOOST_PYTHON_MODULE_INIT(getting_started2)
>     {
>       try
>       {
>         // Create an object representing this extension module.
>         python::module_builder this_module("getting_started2");

>         // Create the Python type object for our extension class.
>         python::class_builder<hello> hello_class(this_module, "hello");

>         // Add the __init__ function.
>         hello_class.def(python::constructor<std::string>());
>         // Add a regular member function.
>         hello_class.def(&hello::greet, "greet");

>         // Add invite() as a regular function to the module.
>         this_module.def(invite, "invite");

>         // Even better, invite() can also be made a member of hello_class!!!
>         hello_class.def(invite, "invite");
>       }
>       catch(...)
>       {
>         python::handle_exception(); // Deal with the exception for Python
>       }
>     }

Now we can use the class normally from Python:

>     >>> from getting_started2 import *
>     >>> hi = hello('California')
>     >>> hi.greet()
>     'Hello from California'
>     >>> invite(hi)
>     'Hello from California! Please come soon!'
>     >>> hi.invite()
>     'Hello from California! Please come soon!'

Notes:

- We expose the class' constructor by calling `def()` on the `class_builder` with an argument whose type is `constructor<`params`>`, where params matches the list of constructor argument types:
- Regular member functions are defined by calling `def()` with a member function pointer and its Python name:
- Any function added to a class whose initial argument matches the class (or any base) will act like a member function in Python.
- To define a nested class, just pass the enclosing `class_builder` (instead of a `module_builder`) as the first argument to the nested `class_builder`'s constructor.

We can even make a subclass of `hello.world`:

>     >>> class wordy(hello):
>     ...     def greet(self):
>     ...         return hello.greet(self) + ', where the weather is fine'
>     ...
>     >>> hi2 = wordy('Florida')
>     >>> hi2.greet()
>     'Hello from Florida, where the weather is fine'
>     >>> invite(hi2)
>     'Hello from Florida! Please come soon!'

Pretty cool! You can't do that with an ordinary Python extension type! Of course, you may now have a slightly empty feeling in the pit of your little pythonic stomach. Perhaps you wanted to see the following `wordy` invitation:

>     'Hello from Florida, where the weather is fine! Please come soon!'

After all, `invite` calls `hello::greet()`, and you reimplemented that in your Python subclass, `wordy`. If so, read on...

Next: Overridable virtual functions Previous: A Simple Example Up: Top

© Copyright David Abrahams 2000. Permission to copy, use, modify, sell and distribute this document is granted provided this copyright notice appears in all copies. This document is provided "as is" without express or implied warranty, and with no claim as to its suitability for any purpose.

Updated: Mar 6, 2001