Exposing a class

This tutorial guides you through the process of exposing your C++ class to Python. Lass::python basically supports two different methods of exposing C++ classes to Python: In shadow mode the translation between both worlds is done using shadow objects which handle all conversions behind the scenes. In native mode the C++ class must be instrumented to handle the Python interface. A user of your Python class available through embedding will not be able to tell the difference between both techniques. The pro's en con's are rather technical and we will keep them for the Advanced Lass::python techniques (like every self-respecting library writer we also have an advanced section, yay).

This tutorial contains following paragraphs:

Let us start we define an interesting C++ class called Foo.
class Foo
{
public:
Foo() {}
virtual ~Foo() {}
int publicMember;
int getMember() { return publicMember; }
void setMember(int iMember) { publicMember=iMember; }
int member() const { return publicMember; }
int& member() { return publicMember; }

int overloaded(int iA) { return iA;}
int overloaded(int iA, int iB) { return iA+iB;}
int overloaded(int iA, int iB, int iC) { return iA+iB+iC;}

virtual void virtualFunction() {}

Foo(int, int=5) {}
};

PY_DECLARE_MODULE( embedding )

PY_SHADOW_CLASS( LASS_DLL_EXPORT, PyFoo, Foo )
PY_SHADOW_DOWN_CASTERS( PyFoo )
PY_DECLARE_CLASS_NAME( PyFoo, "Foo" )

PY_CLASS_CONSTRUCTOR_0( PyFoo )

PY_CLASS_PUBLIC_MEMBER( PyFoo, publicMember )
PY_CLASS_PUBLIC_MEMBER_R_NAME( PyFoo, publicMember, "readOnlyPublicMember" )

PY_CLASS_METHOD( PyFoo, getMember )
PY_CLASS_METHOD( PyFoo, setMember )
PY_CLASS_MEMBER_RW_NAME( PyFoo, getMember, setMember, "accessorMember" )

PY_CLASS_MEMBER_RW_NAME( PyFoo, coolMember, coolMember, "cool" )

PY_CLASS_METHOD_QUALIFIED_1( PyFoo, overloaded, int, int )
PY_CLASS_METHOD_QUALIFIED_2( PyFoo, overloaded, int, int, int )
PY_CLASS_METHOD_QUALIFIED_3( PyFoo, overloaded, int, int, int, int )

PY_CLASS_METHOD( PyFoo, virtualFunction )
PY_CLASS_CONSTRUCTOR_1( PyFoo, int )
PY_CLASS_CONSTRUCTOR_2( PyFoo, int, int )

PY_EXTENSION_MODULE( embedding )

Declaring a shadow class

PY_SHADOW_CLASS( LASS_DLL_EXPORT, PyFoo, Foo )
PY_SHADOW_DOWN_CASTERS( PyFoo )
PY_DECLARE_CLASS_NAME( PyFoo, "Foo" )
The PY_SHADOW_CLASS macro tells lass::python that a C++ shadow class will be created for use in Python. In this case the shadow class PyFoo is created for the regular C++ class Foo. Shadow casters are routines/objects that are responsible for creating shadow objects wherever that should be necessary. An example is when objects of your regular C++ Foo are being used as argument or return value in another shadow class. In general it is a good idea to provide shadow casters, they present no overhead when they are not actively used. PY_DECLARE_CLASS_NAME associates a name for use in Python for the shadow class.

Constructors

PY_CLASS_CONSTRUCTOR_0( PyFoo )
The macro above makes sure that you can create Foo objects in Python. In this case the default constructor is made available. If you have multiple constructors you can just put the other macros exporting those below PY_DECLARE_CLASS_NAME. lass::python will try to match any Python calls for your C++ constructors in a best effort way. This mechanism is similar to overloading so we refer to that paragraph for more information.

Public members

PY_CLASS_PUBLIC_MEMBER( PyFoo, publicMember )
PY_CLASS_PUBLIC_MEMBER_R_NAME( PyFoo, publicMember, "readOnlyPublicMember" )
The PY_CLASS_PUBLIC_MEMBER_XXX macros are used to make public members to your shadow Python class. The first macro adds the public member publicMember from the C++ class Foo to the shadow class and leaves the name intact. The next macro defines a read-only member (in Python) readOnlyPublicMember and use the C++ publicMember public member as data source.

Member functions

PY_CLASS_METHOD( PyFoo, getMember )
PY_CLASS_METHOD( PyFoo, setMember )
The PY_CLASS_METHOD macros expose a member function to Python. Without the _NAME suffix the name of the member function in python is equal to that of the C++ method.

Translating accessor functions

PY_CLASS_MEMBER_RW_NAME( PyFoo, getMember, setMember, "accessorMember" )
PY_CLASS_MEMBER_RW_NAME( PyFoo, coolMember, coolMember, "cool" )
Typically when exposing your C++ class to Python the interface visible in Python needs to be as much Pythonic as possible. lass::python has support for exposing getters and setters as a public member variable in Python. In the example given above any assignments to the accessorMember will be rerouted to the setMember member function of the C++ class. Any requested r-values will go through the getMember function.
Often in C++ you will also have overloaded getter/setters. lass::python allows to specify those as well and will try to match the correct function for getting a value (ie, the const function) and the other one for l-value use.

Overloaded functions

PY_CLASS_METHOD_QUALIFIED_1( PyFoo, overloaded, int, int )
PY_CLASS_METHOD_QUALIFIED_2( PyFoo, overloaded, int, int, int )
PY_CLASS_METHOD_QUALIFIED_3( PyFoo, overloaded, int, int, int, int )
When overloaded functions need to be exported to Python the ambiguity needs to be resolved. Therefor the _QUALIFIED_X suffix has to be used after the macro name. In the macro the arguments of the function have to be given so lass::python knows which function to choose. The _X suffix is filled in with the number of arguments for the function given.

Virtual functions

PY_CLASS_METHOD( PyFoo, virtualFunction )
For lass::python there is nothing special about virtual functions, so you can treat them as regular member functions. Even abstract methods can be treated like any other member method. More info on what behaviour this induces in child-classes is given in another tutorial.

Default arguments

PY_CLASS_CONSTRUCTOR_1( PyFoo, int )
PY_CLASS_CONSTRUCTOR_2( PyFoo, int, int )
The example for default arguments picked out the constructor for default arguments but in fact any other function with default arguments can be exposed to Python in a similar way.