如何通过SWIG为C++类提供Python的__repr__()方法

8 投票
3 回答
2014 浏览
提问于 2025-04-17 16:42

我注意到,当你在Python的交互式环境中输入

help

时,会得到

Type help() for interactive help, ...

而当你输入

help()

时,会进入帮助模式。我觉得这是因为site._Helper定义了__repr__()(第一个例子)和__call__()(第二个例子)。

我很喜欢这种行为(只输入对象就能提示,使用可调用的语法),我想在通过SWIG导出到Python的C++类中实现同样的效果。这是我尝试做的一个简单例子

helpMimic.h
-----------
class HelpMimic
{
public:
    HelpMimic() {};
    ~HelpMimic() {};

    char *__repr__();
    void operator()(const char *func=NULL);
};

helpMimic.cxx
-------------
char *HelpMimic::__repr__()
{
    return "Online help facilities are not yet implemented.";
}

void HelpMimic::operator()(const char *func)
{
    log4cxx::LoggerPtr transcriptPtr = oap::getTranscript();
    std::string commentMsg("# Online help facilities are not yet implemented. Cannot look up ");
    if (func) {
        commentMsg += func;
    }
    else {
        commentMsg += "anything.";
    }

    LOG4CXX_INFO(transcriptPtr, commentMsg);
}

helpMimic.i
-----------
%module sample
 %{
#include <helpMimic.h>
 %}
class HelpMimic
{
public:
    HelpMimic() {};
    ~HelpMimic() {};

    char *__repr__();
    void operator()(const char *func=NULL);
};

当我在我的应用程序中尝试使用这个类时,我似乎无法获得我在帮助中看到的那种行为(下面的输出来自一个嵌入了Python的C++应用程序,每一行输入都通过PyEval_String()发送):

 tam = sample.HelpMimic()
 tam   # echoes 'tam', nothing else
 print tam
 # _5010b70200000000_p_HelpMimic
 print repr(tam)
 # <Swig Object of type 'HelpMimic *' at 0x28230a0>
 print tam.__repr__()
 # Online help facilities are not yet implemented.

最后的print显示了方法__repr__()确实存在,但我无法通过简单的对象引用或使用repr(tam)找到它。我还尝试定义__str()__,希望我误解了哪个会被调用,但仍然没有成功。

我尝试在接口文件中使用%extend指令,将__str__()__repr__()的定义插入到SWIG接口定义文件中,而不是直接在C++中定义,但也没有效果。

我到底遗漏了什么呢?

3 个回答

1

如果你想在Python代码中添加一个__repr__,而不是在C/C++中,你可能需要处理默认的swig定义,__repr__ = _swig_repr

其实这很简单:

#if defined(SWIGPYTHON)
%pythoncode %{
    del __repr__
    def __repr__(self):
        return 'object representation'
%}
#endif
3

我通常使用 %extend 功能,这样就不需要把 C/C++ 代码调整得太针对某个特定的语言。例如:

%extend MyClass {
  %pythoncode %{
    def __repr__(self):
      # How you want your object to be shown
    __swig_getmethods__["someMember"] = SomeMemberGet
    __swig_setmethods__["someMember"] = SomeMemberSet
    if _newclass:
      someMember = property(SomeMemberGet,SomeMemberSet)
    def show(self):
      # You could possibly visualize your object using matplotlib
  %}
};

repr 函数里面,你可以调用几乎任何函数,并且可以把输出格式化成你想要的样子。此外,你还可以添加属性,并定义这些属性是如何与设置器和获取器对应的。

3

正如@flexo在评论中提到的,如果你在使用SWIG代码生成器时加上了-builtin标志,那么repr()这个函数就不会调用你的__repr__方法。相反,你需要定义一个适合用来替代repr的函数。

%feature("python:slot", "tp_repr", functype="reprfunc") HelpMimic::printRepr;

根据HelpMimic::printRepr的要求,这个函数的签名必须和预期的签名匹配(具体可以参考Python文档中的tp_repr)——它必须返回一个字符串或unicode对象。还有一点需要注意的是,你不能把同一个函数放在多个位置,所以不要试图把它用在tp_str上!

撰写回答