Boost.Python 无法解析传递给函数的派生类型
Boost.Python failing to resolve derived type passed to function
我 运行 在我的 Boost.Python 冒险中遇到了另一个障碍。
我定义了以下 Python 模块:
#include <Python.h>
#include <iostream>
#include <boost/python.hpp>
using namespace boost;
using namespace boost::python;
struct Base { };
void foo(boost::shared_ptr<Base>)
{
std::cout << "yay\n";
}
BOOST_PYTHON_MODULE(Test)
{
class_<Base, shared_ptr<Base>, noncopyable>("Base", init<>());
def("foo", foo);
}
运行以下脚本:
from Test import *
class Bar(Base):
def __init__(self):
pass
foo(Base()) #works
foo(Bar()) #error
最后一行产生了这样的错误:
Python argument types in
foo(Bar)
did not match C++ signature:
foo(class boost::shared_ptr<struct Base>)
现在我的问题是为什么这行不通?当然类型系统应该能够计算出 Bar
是一个 Base
实例?
http://coliru.stacked-crooked.com/a/43f111fb3032a20a
感谢任何帮助!
在这种特殊情况下,错误消息具有误导性。该函数接收一个参数 type;但是,该参数有一个不合适的 value。 Bar
初始化程序未初始化其层次结构的 Python Base
部分。 Python 实例不包含 boost::shared_ptr<Base>
实例,导致 Boost.Python 无法调度到 C++ 函数:
class Bar(Base):
def __init__(self):
pass # Base is not initialized.
fun(Base()) # No boost::shared_ptr<Base> instance.
要解决此问题,请在 Bar.__init__()
:
中显式调用 Base.__init__()
class Bar(Base):
def __init__(self):
Base.__init__(self) # Instantiates boost::shared_ptr<Base>.
fun(Bar()) # Boost.Python will extract boost::shared_ptr<Base> from Bar().
有关详细信息,在 Python 中,如果派生 class 定义了 __init__()
方法,则它应该显式调用父 class' __init__()
方法. Python 文档 states:
If a base class has an __init__()
method, the derived class’s __init__()
method, if any, must explicitly call it to ensure proper initialization of the base class part of the instance; for example: BaseClass.__init__(self, [args...])
.
在 Boost.Python 中,C++ class 包装器有一个 instance_holder
。这些对象在其 Python 对象包装器中包含 C++ 实例,并且 C++ 对象的实例化发生在 Python 对象的 __init__
函数中:
When an __init__
function for a wrapped C++ class is invoked, a new instance_holder
instance is created and installed in the Python object [...]
因此,如果不调用Python对象的__init__()
方法,则不会实例化内部C++对象。当从 Python 调用公开的 C++ 函数时,Boost.Python 将检查调用参数,尝试在一组公开的函数中识别匹配的 C++ 函数。当没有找到匹配项时,它将引发 Boost.Python.ArgumentError
异常,列出参数类型和匹配失败的 C++ 函数集。
这是一个完整的示例 demonstrating 有两个不同的 Python 类型继承自公开的 C++ 类型,其中一个层次结构已正确初始化,而另一个未正确初始化:
#include <boost/python.hpp>
struct base {};
void foo(boost::shared_ptr<base>) {}
BOOST_PYTHON_MODULE(example)
{
namespace python = boost::python;
python::class_<base, boost::shared_ptr<base>, boost::noncopyable>(
"Base", python::init<>())
;
python::def("foo", &foo);
}
交互使用:
>>> import example
>>> class GoodDerived(example.Base):
... def __init__(self):
... example.Base.__init__(self)
...
>>> class BadDerived(example.Base):
... def __init__(self):
... pass
...
>>> assert(isinstance(GoodDerived(), example.Base))
>>> assert(isinstance(BadDerived(), example.Base))
>>> try:
... example.foo(GoodDerived())
... got_exception = False
... except:
... got_exception = True
... finally:
... assert(not got_exception)
...
>>> try:
... example.foo(BadDerived())
... got_exception = False
... except:
... got_exception = True
... finally:
... assert(got_exception)
请注意,虽然类型层次结构是正确的并且可以通过 isinstance(()
验证,但这些类型并不表示实例是否具有适当的值。
我 运行 在我的 Boost.Python 冒险中遇到了另一个障碍。
我定义了以下 Python 模块:
#include <Python.h>
#include <iostream>
#include <boost/python.hpp>
using namespace boost;
using namespace boost::python;
struct Base { };
void foo(boost::shared_ptr<Base>)
{
std::cout << "yay\n";
}
BOOST_PYTHON_MODULE(Test)
{
class_<Base, shared_ptr<Base>, noncopyable>("Base", init<>());
def("foo", foo);
}
运行以下脚本:
from Test import *
class Bar(Base):
def __init__(self):
pass
foo(Base()) #works
foo(Bar()) #error
最后一行产生了这样的错误:
Python argument types in
foo(Bar)
did not match C++ signature:
foo(class boost::shared_ptr<struct Base>)
现在我的问题是为什么这行不通?当然类型系统应该能够计算出 Bar
是一个 Base
实例?
http://coliru.stacked-crooked.com/a/43f111fb3032a20a
感谢任何帮助!
在这种特殊情况下,错误消息具有误导性。该函数接收一个参数 type;但是,该参数有一个不合适的 value。 Bar
初始化程序未初始化其层次结构的 Python Base
部分。 Python 实例不包含 boost::shared_ptr<Base>
实例,导致 Boost.Python 无法调度到 C++ 函数:
class Bar(Base):
def __init__(self):
pass # Base is not initialized.
fun(Base()) # No boost::shared_ptr<Base> instance.
要解决此问题,请在 Bar.__init__()
:
Base.__init__()
class Bar(Base):
def __init__(self):
Base.__init__(self) # Instantiates boost::shared_ptr<Base>.
fun(Bar()) # Boost.Python will extract boost::shared_ptr<Base> from Bar().
有关详细信息,在 Python 中,如果派生 class 定义了 __init__()
方法,则它应该显式调用父 class' __init__()
方法. Python 文档 states:
If a base class has an
__init__()
method, the derived class’s__init__()
method, if any, must explicitly call it to ensure proper initialization of the base class part of the instance; for example:BaseClass.__init__(self, [args...])
.
在 Boost.Python 中,C++ class 包装器有一个 instance_holder
。这些对象在其 Python 对象包装器中包含 C++ 实例,并且 C++ 对象的实例化发生在 Python 对象的 __init__
函数中:
When an
__init__
function for a wrapped C++ class is invoked, a newinstance_holder
instance is created and installed in the Python object [...]
因此,如果不调用Python对象的__init__()
方法,则不会实例化内部C++对象。当从 Python 调用公开的 C++ 函数时,Boost.Python 将检查调用参数,尝试在一组公开的函数中识别匹配的 C++ 函数。当没有找到匹配项时,它将引发 Boost.Python.ArgumentError
异常,列出参数类型和匹配失败的 C++ 函数集。
这是一个完整的示例 demonstrating 有两个不同的 Python 类型继承自公开的 C++ 类型,其中一个层次结构已正确初始化,而另一个未正确初始化:
#include <boost/python.hpp>
struct base {};
void foo(boost::shared_ptr<base>) {}
BOOST_PYTHON_MODULE(example)
{
namespace python = boost::python;
python::class_<base, boost::shared_ptr<base>, boost::noncopyable>(
"Base", python::init<>())
;
python::def("foo", &foo);
}
交互使用:
>>> import example
>>> class GoodDerived(example.Base):
... def __init__(self):
... example.Base.__init__(self)
...
>>> class BadDerived(example.Base):
... def __init__(self):
... pass
...
>>> assert(isinstance(GoodDerived(), example.Base))
>>> assert(isinstance(BadDerived(), example.Base))
>>> try:
... example.foo(GoodDerived())
... got_exception = False
... except:
... got_exception = True
... finally:
... assert(not got_exception)
...
>>> try:
... example.foo(BadDerived())
... got_exception = False
... except:
... got_exception = True
... finally:
... assert(got_exception)
请注意,虽然类型层次结构是正确的并且可以通过 isinstance(()
验证,但这些类型并不表示实例是否具有适当的值。