如何使用 SWIG 为 C++ 类提供 Python __repr__()

Posted

技术标签:

【中文标题】如何使用 SWIG 为 C++ 类提供 Python __repr__()【英文标题】:How to Give a C++ Class a Python __repr__() with SWIG 【发布时间】:2013-02-07 11:12:07 【问题描述】:

我观察到当一种类型时

help

在 Python repl 中,一个得到

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);
;

当我尝试在我的应用程序中使用这个类时,我似乎无法获得通过 help 看到的行为(下面的输出取自嵌入了 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++ 中定义它们,但无济于事。

我错过了什么?

【问题讨论】:

刚刚试过你的代码,对我来说很好。我注释掉了 LOG4CXX* 行,因为我没有必要的东西来编译它,但除此之外,我什么也没做。它起作用了......为了记录,我在OSX10.8上使用python2.7。不知道我的设置与您的设置有何不同。看来,无论您缺少什么,它都与代码本身无关 谢谢。我希望我能找出导致我看到的输出的不同之处...... 我同意这绝对是非常奇怪的...... 如何将repr定义为const char* __repr__() const 你在为此调用 swig 时是否使用-builtin 【参考方案1】:

正如@flexo 在评论中建议的那样,如果您将-builtin flag 用于 SWIG 代码生成器,repr() 将不会调用您的 __repr__ 方法。相反,您需要定义一个适合 repr 槽的函数。

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

根据 HelpMimic::printRepr 必须具有与预期签名匹配的签名 (tp_repr in Python docs) - 它必须返回字符串或 unicode 对象。另一个警告 - 您不能将相同的函数放在多个插槽中,所以不要尝试将它用于 tp_str!

【讨论】:

致未来的我(或任何与我类似情况的人):语法,尤其是 HelpMimic::printRepr 部分,也适用于将 C 库绑定到 Python 时。不要忘记 %extend 你的班级使用 printRepr 函数。要扩展的类的名称可以从生成的 C 代码中获取,也可以通过在 C 库中查找相关结构来绑定。【参考方案2】:

我通常使用 %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 函数中的位置基本上可以调用任何函数并格式化输出以满足您的需要。此外,您可以添加属性并定义它们如何映射到 setter 和 getter。

【讨论】:

当使用 SWIG 的 -builtin 标志时,这似乎不起作用。 它没有。 SWIG 的文档也这么说。我建议您完全避免使用内置标志 您能详细说明一下您的推荐吗? 我会用读/写属性和函数的例子来更新答案。

以上是关于如何使用 SWIG 为 C++ 类提供 Python __repr__()的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 SWIG 从 lua 中的 C++ 类继承

使用 swig 使 C++ 类看起来像一个 numpy 数组

使用 SWIG,如何将 C++ void func(Class& out) 包装为 C# Class func()?

SWIG:如何将 C++ 对象数组从 C# 传递到 C++?

使用 SWIG 包装调用另一个对象成员函数的 C++ 类

如何使用swig为c++生成php接口so