从Boost python模块内部的pyside导入类? [英] import classes from pyside inside of a boost python module?

查看:85
本文介绍了从Boost python模块内部的pyside导入类?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想使用PySide定义基本的QT类以及C ++和python之间的映射,但是要在独立的python代码中以及使用boost :: python从嵌入式python中做到这一点.

I'd like to use PySide to define the basic QT classes and the mapping between C++ and python, but to do so in both standalone python code and from embedded python using boost::python.

首先,返回QPointF的模块定义和类:

First, the module definition and class returning QPointF:

QPointF  X::getY() { 
  return QPointF(); 
}    

BOOST_PYTHON_MODULE(myBoostPythonModule)
{
// is there some magic init/register commands to put here?
boost::python::api::object module     = import("__main__");
boost::python::api::object name_space = module.attr("__dict__");
boost::python::exec("from PySide.QtCore import *",name_space,name_space);
boost::python::exec("import sys,os\nprint(sys.modules)",name_space,name_space);

class_<X, boost::noncopyable>(
            "X", init<const char*>())
        .def("getY",&X::getY)
        ;
}

现在,应用程序的嵌入式python代码,最后一行失败了,我想知道如何解决:

Now, the application's embedded python code, last line is what fails and I'm wondering how to get around:

execute("import myBoostPythonModule");     // OK
execute("x=myBoostPythonModule.X('foo')"); // OK

execute("w=QPointF()\nprint(w)");          // OK
// PySide.QtCore.QPointF(0.000000, 0.000000)

execute("y=x.getY()");                     // FAIL:
// TypeError: No to_python (by-value) converter found for C++ type: QPointF

这是怎么回事,我可以创建一个QPointF,但是名称在某种程度上不受python和c ++的限制吗?我是否在模块中缺少一些导入内容以告知要从PySide导入?

What's going on here, I can create a QPointF, but the name somehow isn't bound between python and c++ ? Am I missing some imports in the module to tell it to import from PySide?

推荐答案

PySide为Qt绑定提供 Shiboken . Shiboken生成支持自己的类型转换系统的Python C API绑定.这些转换的知识位于Shiboken生成的绑定中,而不是Python类型系统中.因此,PySide知道如何将QPointF对象转换为C ++/Python. Python的类型系统没有.

PySide provides its Qt bindings with Shiboken. Shiboken generates Python C API bindings that supporting its own type conversion system. The knowledge of these conversions resides within the Shiboken generated bindings, and not the Python type system. Thus, PySide knows how to convert a QPointF object to/from C++/Python; Python's type system does not.

当对象通过通过Boost.Python公开的函数进行转换时,Boost.Python将检查其注册表中是否存在适当的类型转换器.这些转换器为Boost.Python提供了有关如何通过Boost.Python公开的类型与C ++/Python进行相互转换的知识.因此,当Boost.Python尝试将QPointF C ++类型返回给Python时,由于转换尚未在Boost.Python中注册,因此会引发异常.

When an object transitions through a function exposed with Boost.Python, then Boost.Python will check its registry for the appropriate type converter. These converters provide Boost.Python with knowledge on how to convert to/from C++/Python for types exposed through Boost.Python. Hence, when Boost.Python tries to return a QPointF C++ type to Python, it throws an exception as the conversion has not been registered with Boost.Python.

这是带注释的代码:

import myBoostPythonModule
from PySide.QtCore import *
...
x=myBoostPythonModule.X('foo') # Boost.Python knows how to convert C++ X
                               # to Python X.  Python's type system does not.

w=QPointF()                    # Shiboken knows how to convert C++ QPointF to
                               # Python QPointF.  Python's type system does not.
print(w)                       # Shiboken knows how to represent C++ QPointF as
                               # a string.

y=x.getY()                     # Boost.Python knows how to invoke X::getY(),
                               # but only Shiboken knows how to convert C++
                               # QPointF to Python QPointF.  Thus, the TypeError
                               # exception is raised.


可以实现Boost.Python的 Shiboken类型转换器示例,下面是一个用Shiboken的旧类型转换器实现的Boost.Python转换器的完整示例.我本可以使用新的Shiboken类型转换器API,但根据文档尚不清楚它是什么.


It is possible to implement Boost.Python's converters in terms of another implementation. Expanding upon the Shiboken type converter example, below is a complete example of Boost.Python's converters implemented with Shiboken's old type converter. I would have used the new Shiboken type converter API, but it was unclear to me as to what it is based on the documentation.

#include <iostream>

#include <boost/python.hpp>

/// @brief Mockup Complex class from Shiboken documentation.
class Complex
{
public:
  Complex(double real, double imaginary)
    : real_(real),
      imaginary_(imaginary)
  {}

  double real() const      { return real_;      }
  double imaginary() const { return imaginary_; }

private:
  double real_;
  double imaginary_;
};

/// @brief Mocked up Shiboken converter.
namespace Shiboken {

template <typename> struct Converter;

template <> struct Converter<Complex>
{
public:
  // ...

  static inline bool isConvertible(PyObject* pyObj)
  {
    std::cout << "Shiboken::Converter<Complex>::isConvertible()" << std::endl;
    return PyComplex_Check(pyObj);
  }

  // ...

  static inline PyObject* toPython(const Complex& cpx)
  {
    std::cout << "Shiboken::Converter<Complex>::toPython()" << std::endl;
    return PyComplex_FromDoubles(cpx.real(), cpx.imaginary());
  }

  static inline Complex toCpp(PyObject* pyobj)
  {
    std::cout << "Shiboken::Converter<Complex>::toCpp()" << std::endl;
    double real      =  PyComplex_RealAsDouble(pyobj);
    double imaginary =  PyComplex_ImagAsDouble(pyobj);
    return Complex(real, imaginary);
  }
};
} // namespace Shiboken

/// @brief Type used to convert a complex to Python.
struct complex_converter_to_python
{
  static PyObject* convert(const Complex& c)
  {
    // Delegate to Shiboken.
    std::cout << "complex_converter_to_python::convert()" << std::endl;
    return Shiboken::Converter<Complex>::toPython(c);
  }
};

/// @brief Type that registers a Python Complex type to C++
///        Complex when passing through Boost.Python.
struct complex_converter_from_python
{
  /// @note Registers converter from a python complex to C++ complex.
  complex_converter_from_python()
  {
    boost::python::converter::registry::push_back(
      &complex_converter_from_python::convertible,
      &complex_converter_from_python::construct,
      boost::python::type_id<Complex>());
  }

  /// @brief Check if PyObject is a Complex.
  static void* convertible(PyObject* object)
  {
    // Delegate to Shiboken.  Based on the documentation, the
    // isConvertible function is gone, so explicit checking may
    // be required based on the version of Shiboken.
    std::cout << "complex_converter_from_python::convertible()" << std::endl;
    return Shiboken::Converter<Complex>::isConvertible(object)
      ? object 
      : NULL;
  }

  /// @brief Convert Python Complex to C++ Complex.
  static void construct(
    PyObject* object,
    boost::python::converter::rvalue_from_python_stage1_data* data)
  {
    // Obtain a handle to the memory block that the Boost.Python
    // converter has allocated for the C++ type.
    namespace python = boost::python;
    typedef python::converter::rvalue_from_python_storage<Complex>
                                                                storage_type;
    void* storage = reinterpret_cast<storage_type*>(data)->storage.bytes;

    // In-place construct a Complex type via copy-constructor, passing
    // in a Complex created from Shiboken.
    std::cout << "complex_converter_from_python::construct()" << std::endl;
    data->convertible = new (storage) Complex(
      Shiboken::Converter<Complex>::toCpp(object));
  }
};

/// @brief Factory function used to exercise to-python conversion.
Complex make_complex(double real, double imaginary)
{
  return Complex(real, imaginary);
}

/// @brief Printing function used to exercise from-python converison.
void print_complex(const Complex& c)
{
  std::cout << "In print_complex: "
            << c.real() << ", "
            << c.imaginary() << std::endl;
}

BOOST_PYTHON_MODULE(example)
{
  namespace python = boost::python;

  // Register Complex from python converter.
  complex_converter_from_python();

  // Register Complex to python converter.
  python::to_python_converter<
    Complex,
    complex_converter_to_python>();

  python::def("make_complex",  &make_complex);
  python::def("print_complex", &print_complex);
}

及其用法:

>>> import example
>>> x = example.make_complex(4, 2)
complex_converter_to_python::convert()
Shiboken::Converter<Complex>::toPython()
>>> example.print_complex(x)
complex_converter_from_python::convertible()
Shiboken::Converter<Complex>::isConvertible()
complex_converter_from_python::construct()
Shiboken::Converter<Complex>::toCpp()
In print_complex: 4, 2

替代方法虽然不是最优雅的方法,但可以让Boost.Python公开的函数使用boost::python::object类型,并通过Python语句与对象进行接口.类似于:

Alternative, while not the most elegant of approaches, one could have the functions exposed from Boost.Python use boost::python::object types, and interface with the object via Python statements. Something similar to:

boost::python::object X::getY()
{ 
  return boost::python::exec("QPointF()", ...); 
}

上面的代码将让Python实例化一个QPointF Python对象,该对象将委托给Shiboken的类型系统.由于X::getY()返回一个通用对象,当对象句柄从C ++转换为Python时,Boost.Python将不会尝试执行类型转换.

The above code will have Python instantiate a QPointF Python object, which will delegate to Shiboken's type system. As X::getY() returns a generic object, Boost.Python will not attempt to perform type conversions when the object handle transitions from C++ to Python.

这篇关于从Boost python模块内部的pyside导入类?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆