PySide提供了Qt的绑定与Shiboken。 Shiboken生成支持其自己的类型转换系统的Python C API绑定。这些转换的知识存在于Shiboken生成的绑定中,而不是Python类型的系统。因此,PySide知道如何将一个QPointF
对象转换为C++/Python; Python的类型系统没有。
当通过与Boost.Python的暴露的功能的对象转变,然后Boost.Python的将检查其注册表中的适当的类型转换器。这些转换器为Boost.Python提供了关于如何将通过Boost.Python公开的类型转换为C++/Python的知识。因此,当Boost.Python的尝试将QPointF
C++型返回到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的converters在另一个实施方面。扩大后的Shiboken type converter example,下面是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()", ...);
}
上面的代码将具有的Python实例化一个QPointF
Python对象,这将委托给Shiboken的类型系统。作为X::getY()
返回一个通用对象,Boost.Python的将不尝试执行类型转换当对象处理来自C++转变到Python。
但是,是不是有一个全球性的蟒蛇转换器列表?例如,如果您尝试为QString注册两个转换器,则会出现运行时错误。我认为这有一个更优雅的解决方案,它只是从shiboken调用适当的注册函数,例如正如这个人试图在这里做的:http://www.mail-archive.com/[email protected]/msg00952.html –
@peterkarasev:Boost.Python类型转换器的底层注册表是一个单例。我扩展了Boost.Python中转换器的显示答案,以及如何使用另一个API实现它们。在这种情况下,我使用了您提供的链接中提到的API。 –
是的,这是正确的想法,虽然该链接中的API似乎不正确。 “根据对Shiboken :: Conversions和Shiboken :: Module的调用注册boost :: python转换器”是我正常工作的。 –