Python从C+;创建对现有Python对象的新引用+; 我使用Posi.Python包装C++类 x>代码>。在创建此类的对象时,我想在本地名称空间中插入对该对象的附加引用(这样我就可以用固定名称引用他新创建的对象,比如说lastX)。我试过了 要在X::X()构造函数中执行此操作,请使用 X::X() { boost::python::object locals(boost::python::borrowed(PyEval_GetLocals())); boost::python::object me(this); locals["lastX"]=me; }

Python从C+;创建对现有Python对象的新引用+; 我使用Posi.Python包装C++类 x>代码>。在创建此类的对象时,我想在本地名称空间中插入对该对象的附加引用(这样我就可以用固定名称引用他新创建的对象,比如说lastX)。我试过了 要在X::X()构造函数中执行此操作,请使用 X::X() { boost::python::object locals(boost::python::borrowed(PyEval_GetLocals())); boost::python::object me(this); locals["lastX"]=me; },python,c++,initialization,boost-python,Python,C++,Initialization,Boost Python,但这不起作用(lastX已创建,但它没有引用任何内容;从Python打印它会导致segfault)。我可能应该使用我自己的init函数,但我也不知道如何获取对新创建的Python对象的引用 有什么想法吗?谢谢。要完成此操作,必须修改调用堆栈上的另一帧。请注意,这取决于Python实现。例如,在Python2.7中,模块和可用于在特定帧上修改 我强烈建议使用Python解决方案,正如在回答中所做的那样,并对所需的类“\uuuu init\uu函数进行monkey补丁。例如,下面将修补Spam类,以

但这不起作用(
lastX
已创建,但它没有引用任何内容;从Python打印它会导致segfault)。我可能应该使用我自己的
init
函数,但我也不知道如何获取对新创建的Python对象的引用


有什么想法吗?谢谢。

要完成此操作,必须修改调用堆栈上的另一帧。请注意,这取决于Python实现。例如,在Python2.7中,模块和可用于在特定帧上修改

我强烈建议使用Python解决方案,正如在回答中所做的那样,并对所需的类“
\uuuu init\uu
函数进行monkey补丁。例如,下面将修补
Spam
类,以将名为
last\u Spam
的变量插入调用方的框架中,该变量引用新构造的
Spam
实例:

def\u patch\u init(cls,名称):
cls_init=getattr(cls,'.'初始化'.'无)
def补丁(自我):
调用方\帧=检查。当前帧(1)
new_locals=调用方_frame.f_locals
新本地人[姓名]=自我
_强制局部变量(调用方局部变量帧、新局部变量)
如果cls_init:
cls_init(自我)
setattr(cls,'.'初始化'.'补丁)
_补丁_init(垃圾邮件,“最后一个垃圾邮件”)
spam=spam()
断言(垃圾邮件是最后的垃圾邮件)

然而,Boost.Python也可以实现同样的功能。要做到这一点,必须:

  • 修改帧的
    局部变量()
  • 在对象构造期间访问
    self
    实例
请注意,这些可能是相当超前的话题

修改帧的
locals()

这是与回答中使用的方法相同的方法,它依赖于Python实现,但用C++编写。在大多数执行路径中,帧的

locals()
不能写入新变量。但是,当启用系统跟踪时,调试器和其他工具经常使用的帧跟踪函数可以修改帧的
locals()

//@简短跟踪签名类型。Python需要MPL签名才能访问
///自定义函子。
typedef boost::mpl::vector<
boost::python::object,//返回
boost::python::object,//frame
boost::python::object,//事件
boost::python::object//argt
>跟踪\签名\类型;
///@brief是Python的noop函数。返回无。
boost::python::objectnoop(
boost::python::tuple/*args*/,,
boost::python::dict/*kw*/
)
{
返回boost::python::object();
}
///@brief在提供的框架中注入新的_局部变量。
void将\u局部变量\u注入到\u框架中(
boost::python::对象框架,
boost::python::dict new_locals
)
{
名称空间python=boost::python;
//通过将全局跟踪函数设置为任何非无来强制跟踪
//功能。
//#如果不是sys.gettrace():
如果(!PyThreadState_Get()->c_tracefunc)
{
//使用sys.settrace函数防止需要重新实现
//追踪蹦床。
//#导入系统
python::objectsys(python::handle(PyImport_ImportModule(“sys”));
//#sys.settrace(lambda*args,**键:无)
sys.attr(“uu dict_uuu”)[“settrace”](python::raw_函数(&detail::noop));
}
//创建跟踪函数。
//#def跟踪(帧、事件、参数):
python::object trace=python::make_函数([new_locals](
python::对象框架,
python::object/*事件*/,,
python::object/*arg*/
)
{
//更新帧的局部变量。
//#frame.f_locals.update(新_locals)
frame.attr(“f_locals”).attr(“update”)(新的_locals);
//将帧设置为使用默认跟踪,以防止出现这种情况
//跟踪函子在每次跟踪调用时重置局部变量。
//#del frame.f#u trace
frame.attr(“f_trace”).del();
//#不返回
返回boost::python::object();
},
python::默认调用策略(),
跟踪\签名\类型());
//设置帧以使用自定义跟踪。
//#frame.f_trace=跟踪
frame.attr(“f_跟踪”)=跟踪;
}
使用上述代码,可以使用
将\u注入到\u frame\u locals()
来更新给定帧的局部变量。例如,以下内容将在当前帧中添加引用
42
的变量
x

//创建将注入当前帧的字典。
名称空间python=boost::python;
python::dict new_locals;
新的本地人[“x”]=42;
//获取当前帧的句柄。
python::对象框架(python::借用)(
重新解释cast(PyEval_GetFrame());
//设置要注入帧的局部变量。
将\注入\帧\局部变量(帧,新\局部变量);

在对象构造期间访问
self
实例。

给定C++对象,不能使用Boosi.python API来定位对象所在的Python对象。因此,我们必须像Boost一样访问

self
。Python正在构建对象

有几个自定义点:

  • 在构造过程中修改要公开的类以接受
    PyObject*
    。可以让Boost.Python提供
    PyObject*
    实例来专门化:

    structfoo
    {
    //构造器。
    foo(PyObject*self)
    {
    名称空间python=boost::python;
    python::句柄(python::借用(self));
    trace::将\注入\当前\帧(“last\ foo”,python::object(handle));
    }
    //Python复制构造函数。
    foo(PyObject*self,const foo&/*rhs*/)
    {
    名称空间python=boost::python;
    python::handle句柄(python::借用(self)