2

PySide を使用して、基本的な QT クラスと C++ と python の間のマッピングを定義したいと思いますが、これはスタンドアロンの python コードと、boost::python を使用した組み込み python の両方で行います。

まず、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 コード、最後の行が失敗したものであり、どうやって回避するのか疑問に思っています:

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 からインポートするように指示するためのインポートがいくつかありませんか?

4

2 に答える 2

2

PySide は、その Qt バインディングにShibokenを提供します。Shiboken は、独自の型変換システムをサポートする Python C API バインディングを生成します。これらの変換の知識は、Python 型システムではなく、Shiboken によって生成されたバインディング内に存在します。QPointFしたがって、PySide はオブジェクトを C++/Python との間で変換する方法を知っています。Python の型システムはそうではありません。

Boost.Python で公開された関数を介してオブジェクトが遷移すると、Boost.Python は適切な型コンバーターのレジストリをチェックします。これらのコンバーターは、Boost.Python を介して公開された型を C++/Python との間で変換する方法に関する知識を Boost.Python に提供します。したがって、Boost.Python がQPointFC++ 型を Python に返そうとすると、変換が 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 を使用したかったのですが、それが何に基づいているのか、ドキュメントではわかりませんでした。

#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 ステートメントを介してオブジェクトとインターフェイスさせることができます。次のようなもの:

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

上記のコードは、QPointFPython オブジェクトをインスタンス化し、Shiboken の型システムに委譲します。AsX::getY()はジェネリック オブジェクトを返します。Boost.Python は、オブジェクト ハンドルが C++ から Python に移行するときに型変換を実行しようとしません。

于 2013-08-31T05:40:34.887 に答える
1

以前の返信と私が見つけた他の情報に基づいて、入力引数を期待するラップPySide.QtGui.QColorされた C++ メソッドに引数のようなものを渡すことを許可する、やや一般的なルーチンを次に示します。boost::pythonQColor&

template<class QtGuiClass,int SBK_BOGAN_IDX>
struct QtGui_from_python {
QtGui_from_python() {
  qDebug()<<" registering type: " << typeid(this).name() << " in " << __FUNCTION__;
  boost::python::converter::registry::push_back(
    &convertible,
    &construct,
    boost::python::type_id<QtGuiClass>());
}
static void* convertible(PyObject* obj_ptr) {
    if(!PyObject_TypeCheck(obj_ptr,
            (PyTypeObject*)XSbkPySide_QtGuiTypes[SBK_BOGAN_IDX]))
    {    qDebug()<<"Failed type check!?"; }
    return obj_ptr;
}
static void construct( PyObject* obj_ptr, 
   bp::converter::rvalue_from_python_stage1_data* data)
{
    void* storage = (
    (boost::python::converter::rvalue_from_python_storage<QtGuiClass>*)
    data)->storage.bytes;

    SbkObject* result = reinterpret_cast<SbkObject*>(obj_ptr);
    auto _ptr = (QtGuiClass*) (Shiboken::Object::cppPointer(
                                       result,Py_TYPE(result)));
    new (storage) QtGuiClass(*_ptr);
    qDebug() << "__alloc'd " << typeid(*_ptr).name() <<" at "<<_ptr;
    data->convertible = storage;
}
};

そして、起動関数から上記を呼び出します。

QtGui_from_python<QColor,SBK_QCOLOR_IDX>();
于 2014-01-01T22:38:43.803 に答える