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:- Shadow objects : C++ objects and Python objects live in a separate world.
- Native objects : C++ objects and Python objects share the same mixed world.
This tutorial contains following paragraphs:
- declaring a class
- constructors
- public members
- member functions
- translating accessor functions
- overloaded functions
- virtual functions
- default values
class Foo
{
public:
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 )
{
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) {}
};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.
PY_SHADOW_DOWN_CASTERS( PyFoo )
PY_DECLARE_CLASS_NAME( PyFoo, "Foo" )
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.
PY_CLASS_PUBLIC_MEMBER_R_NAME( PyFoo, publicMember, "readOnlyPublicMember" )
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.
PY_CLASS_METHOD( PyFoo, setMember )
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.
PY_CLASS_MEMBER_RW_NAME( PyFoo, coolMember, coolMember, "cool" )
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.
PY_CLASS_METHOD_QUALIFIED_2( PyFoo, overloaded, int, int, int )
PY_CLASS_METHOD_QUALIFIED_3( PyFoo, overloaded, int, int, int, int )
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.
PY_CLASS_CONSTRUCTOR_2( PyFoo, int, int )