如何通过SWIG为C++类提供Python的__repr__()方法
我注意到,当你在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 个回答
如果你想在Python代码中添加一个__repr__
,而不是在C/C++中,你可能需要处理默认的swig定义,__repr__ = _swig_repr
。
其实这很简单:
#if defined(SWIGPYTHON)
%pythoncode %{
del __repr__
def __repr__(self):
return 'object representation'
%}
#endif
我通常使用 %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 函数里面,你可以调用几乎任何函数,并且可以把输出格式化成你想要的样子。此外,你还可以添加属性,并定义这些属性是如何与设置器和获取器对应的。
正如@flexo在评论中提到的,如果你在使用SWIG代码生成器时加上了-builtin
标志,那么repr()
这个函数就不会调用你的__repr__
方法。相反,你需要定义一个适合用来替代repr的函数。
%feature("python:slot", "tp_repr", functype="reprfunc") HelpMimic::printRepr;
根据HelpMimic::printRepr的要求,这个函数的签名必须和预期的签名匹配(具体可以参考Python文档中的tp_repr)——它必须返回一个字符串或unicode对象。还有一点需要注意的是,你不能把同一个函数放在多个位置,所以不要试图把它用在tp_str上!