Swig与Python - 不同的对象实例化

1 投票
1 回答
603 浏览
提问于 2025-04-17 18:12

我有一个关于在Python和C++中生成的swig包装对象的问题。假设我有以下简单的C++类定义:

#include <vector>

class Sphere
{
public:
    Sphere(){};
};

class Container
{
public:
    Container() : data_(0) {};

    void add() {
        data_.push_back(Sphere());
    }

    Sphere & get(int i) { return data_[i]; }

    std::vector<Sphere> data_;
};

还有以下的swig设置:

%module engine
%{
#define SWIG_FILE_WITH_INIT
#include "sphere.h"
%}

// -------------------------------------------------------------------------
// Header files that should be parsed by SWIG
// -------------------------------------------------------------------------
%feature("pythonprepend") Sphere::Sphere() %{
    print 'Hello'
%}
%include "sphere.h"

如果我在Python中执行以下操作:

import engine
sphere_0 = engine.Sphere()
container = engine.Container()
container.add()
sphere_1 = container.get(0)

那么第一次创建包装的Sphere类实例时,会调用Python包装接口的init方法(会打印'Hello')。

但是第二次在C++端生成实例时,就不会调用这个方法(不会打印'Hello')。

因为我的目标是能够在对象构造时添加额外的Python功能,所以我很希望能听到大家有什么好的建议,来正确实现这两种实例化场景。

最好的祝愿,

Mads

1 个回答

1

我通常在接口文件中用明确的 pythoncode 块来做事情,像这样:

%pythoncode %{
def _special_python_member_function(self):
     print "hello"
     self.rotate() # some function of Sphere
Sphere.new_functionality=_special_python_member_function
%}

这样你就可以在SWIG接口提供的功能基础上,给这个类添加任意的Python功能。你可能需要把一些C语言的功能 rename(重命名)一下,但这样做应该能让你得到所有想要的成员 函数

我从来没有尝试过以这种方式重新映射 __init__,所以我不知道这样会有什么效果。如果假设这样不行的话,你就无法确保Python对象在创建时有特定的内部状态(成员变量)。

你将不得不进行懒惰评估:

def function_that_depends_on_python_specific_state(self, *args):
   if not hasatttr( self, 'python_data'):
        self.python_data = self.make_python_data() # construct the relevant data
   pass # do work that involves the python specific data

并检查Python特定数据是否存在。如果只有几种情况,我会像上面那样把它放在函数里。不过,如果这样做变得很麻烦,你可以修改 __getattr__,让它在访问时构建Python特定的数据成员。

def _sphere_getattr(self, name):
    if name=='python_data':
         self.__dict__[name]=self.make_python_data()
         return self.__dict__[name]
    else:
        raise AttributeError
Sphere.__getattr__ = _sphere_getattr

在我看来,如果你有大量新的功能和数据,这些功能和数据与底层的C实现无关,那么实际上你是在问:“我该如何让我的Python Sphere类成为C Sphere类的子类,同时保持它们是同一种类型?”

撰写回答