preface
The difference of data types between python and c + + is a common problem in conversion. Some simple data types can be used in general, but many middle types cannot be used directly. When encountering such problems, boost The extract class provided by python is a convenient solution. This article is used to record my understanding of extract in use.
1. Description
1.1 introduction to extract
Extract is boost Python is a class used to extract C + + objects from Python objects. Through this class, we can convert some Python objects into C + + language objects. For example, convert a variable of type boost::python::str into a variable of type char *.
The executive member of Extract must be a non overloaded static function whose single parameter is a python object type. Acceptable Python object types include those public (and explicit) object types derived from PyObject and POD types compatible with PyObject layout.
Note: to extract a c + + type from a python object, the object must first contain this type of content.
1.2 application method
Here are some basic usage methods.
1. Get the value of python object
int a = boost::python::extract<int>(x)
Extract the contents of int from python object x.
2. Check with constructor before extraction
int g(object x) { extract<int> get_int(x); if (get_int.check()) return get_int(); else return 0; }
Constructor get_int first calls check() to check whether x can be converted into int type data.
3. Use extract to modify variable objects directly
We can use extract to modify boost::python::object and its derived objects or PyObject * directly and conveniently without copying the target object.
namespace bp = boost::python; // bp::object x; dict d = bp::extract<bp::dict>(x.attr("__dict__")); d["whatever"] = 3; // modifies x.__dict__ ! // PyObject* pyobj; PyObject* __dict__ = PyObject_GetAttrString(pyobj, const_cast<char*>("__dict__")); // (see also http://article.gmane.org/gmane.comp.python.c%2B%2B/15664) bp::dict dictobj = bp::extract<bp::dict>(__dict__); dictobj["whatever"] = 3; // modifies pyobj __dict___!
4. Extract elements from more complex structures
In order to extract elements from complex structures such as lists and tuples, we must nest extraction calls. Here, suppose there is a list variable with tuple element type, from which the data in tuple is extracted.
boost::python::list l1 = [(1, 2), (3, 4), (5, 6)]; extract<int>(extract<tuple>(list[0])());
2. Examples
For demonstration, add a showrelationships () function in the previous RealWorld class, which converts the passed python list type data into std::vector in c + +.
Declare and define functions
In classes Add a function declaration under RealWorld class of HPP:
void ShowRelatives(boost::python::list &rels);
It is defined as follows:
void RealWorld::ShowRelatives(python::list &rels) { std::vector<char *> rel(len(rels), 0); for (int i = 0; i < len(rels); i++){ rel[i] = python::extract<char *> (rels[i]); } for (int i = 0; i < rel.size(); i++) std::cout << rel[i] << " "; std::cout << std::endl; }
Add to python module
.def ("ShowRelatives", &RealWorld::ShowRelatives, python::args("rels"))
Simple test
The python test procedure is as follows:
#!/usr/bin/env python import classes t1 = classes.RealWorld("Xiangdi", 'm') relative = ("father", "mother", "brother", "sister") t1.ShowRelatives(relative)
Operation results
Note: it seems that python list cannot be directly converted to the form of std::vectorstd::string, because I always report an error when trying this way:
Traceback (most recent call last): File "classes.py", line 9, in <module> t1.ShowRelatives(relative) RuntimeError: basic_string::_M_construct null not valid
3. Detailed explanation of extract class
The extract class is defined in < boost / Python / extract HPP > file.
3.1 extract definition
template <class T> struct extract : converter::select_extract<T>::type { private: typedef typename converter::select_extract<T>::type base; public: typedef typename base::result_type result_type; operator result_type() const { return (*this)(); } extract(PyObject*); extract(api::object const&); };
Where T represents the target c + + type to extract. Two usages are supported:
- extract(o): generates a temporary object that is implicitly converted to t (it can also be explicitly converted through the function call operator of the object). However, if there is no object in o that can be converted to type T, a Python TypeError exception is thrown.
- extract x(o): this method constructs an extractor in which the check() member function asks whether the transformation is available without throwing an exception.
3.2 constructor
extract(PyObject*); extract(api::object const&);
When constructing an extract instance, you can pass in two parameters: a pointer to a Python object and a reference to an object. From the implementation of the two functions, the second method is actually to pass the pointer of the reference object to the parent object inside the function body.
3.3 member functions
Only some member functions are introduced here.
operator result_type() const
result_ The type () function is used to convert the pointer of the stored Python object to t or T & type, that is, the action that will be run automatically after instantiating the extractor. If there is a running error (for example, the python object does not contain T-type content), the function will trigger TypeError.
It can't be seen from the above definition code that the parent class of extract also provides some additional member functions, such as check().
bool check() const;
This function is called in the constructor of extract to check whether the python object can be converted to T or T& type, if false can not be returned. It should be noted that Python exceptions will not be triggered even if they cannot be converted.
reference material
boost:Extractor
Chapter 5. To/From Python Type Conversion
boost.python/extract