Boost: extract the type of c + + language and extract class from python object

Posted by xkaix on Thu, 20 Jan 2022 20:42:56 +0100

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

Topics: Python C++ boost