尝试在IPython中打印对象但不在Python中打印对象

时间:2015-07-07 17:09:39

标签: python ipython python-c-api

尝试显示C扩展中定义的类的对象时出现分段错误。

In [1]: import moose
on node 0, numNodes = 1, numCores = 2

In [2]: a = moose.Neutral('a')

In [3]: print a
<moose.Neutral: id=459, dataIndex=0, path=/a[0]>

In [4]: a
Segmentation fault (core dumped)

我在C中实现了reprstr个函数,但是使用gdb我认为它甚至没有使用这些函数。它适用于同一扩展中的另一个类。标准Python 2.7解释器也可以正常工作。

print a适用于IPython控制台。

我检查了我的refcounts,这似乎没有问题(PyObject_New将refcount初始化为1)。

当我直接在控制台中输入导致段错误的变量标识符时,IPython正在做什么特别的事情?

这是一个非常大的模块,最小的例子是非常重要的。 repr函数定义是:

PyObject * moose_ObjId_repr(_ObjId * self)
{
    if (!Id::isValid(self->oid_.id)){
        RAISE_INVALID_ID(NULL, "moose_ObjId_repr");
    }
    ostringstream repr;
    repr << "<moose." << Field<string>::get(self->oid_, "className") << ": "
         << "id=" << self->oid_.id.value() << ", "
         << "dataIndex=" << self->oid_.dataIndex << ", "
         << "path=" << self->oid_.path() << ">";
    return PyString_FromString(repr.str().c_str());
} // !  moose_ObjId_repr

gdb堆栈跟踪如下。不幸的是,由于Python C-API中的一个微妙问题,我无法使用Python调试版本。看起来分段错误发生在控制到达模块函数之前(模块是使用调试标志构建的,如果我print a,那么repr函数上的断点就会捕获它。)

#0  0x000000000050ffab in ?? ()
#1  0x0000000000503cbc in ?? ()
#2  0x00000000004879ba in ?? ()
#3  0x000000000049968d in PyEval_EvalFrameEx ()
#4  0x00000000004a090c in PyEval_EvalCodeEx ()
#5  0x000000000049ab45 in PyEval_EvalFrameEx ()
#6  0x00000000004a090c in PyEval_EvalCodeEx ()
#7  0x000000000049ab45 in PyEval_EvalFrameEx ()
#8  0x00000000004a1c9a in ?? ()
#9  0x00000000004dfe94 in ?? ()
#10 0x0000000000505f96 in PyObject_Call ()
#11 0x00000000004dddad in ?? ()
#12 0x0000000000499be5 in PyEval_EvalFrameEx ()
#13 0x00000000004a090c in PyEval_EvalCodeEx ()
#14 0x0000000000499a52 in PyEval_EvalFrameEx ()
#15 0x00000000004a090c in PyEval_EvalCodeEx ()
#16 0x000000000049ab45 in PyEval_EvalFrameEx ()
#17 0x00000000004a1c9a in ?? ()
#18 0x00000000004dfe94 in ?? ()
#19 0x0000000000505f96 in PyObject_Call ()
#20 0x00000000004dddad in ?? ()
#21 0x00000000004dc9cb in PyEval_CallObjectWithKeywords ()
#22 0x000000000049cf17 in PyEval_EvalFrameEx ()
#23 0x00000000004a090c in PyEval_EvalCodeEx ()
#24 0x0000000000588d42 in PyEval_EvalCode ()
#25 0x000000000049e460 in PyEval_EvalFrameEx ()
#26 0x00000000004a090c in PyEval_EvalCodeEx ()
#27 0x000000000049ab45 in PyEval_EvalFrameEx ()
#28 0x00000000004a090c in PyEval_EvalCodeEx ()
#29 0x0000000000499a52 in PyEval_EvalFrameEx ()
#30 0x00000000004a090c in PyEval_EvalCodeEx ()
#31 0x0000000000499a52 in PyEval_EvalFrameEx ()
#32 0x00000000004a090c in PyEval_EvalCodeEx ()
#33 0x0000000000499a52 in PyEval_EvalFrameEx ()
#34 0x00000000004a090c in PyEval_EvalCodeEx ()
#35 0x0000000000499a52 in PyEval_EvalFrameEx ()
#36 0x00000000004a090c in PyEval_EvalCodeEx ()
#37 0x000000000049ab45 in PyEval_EvalFrameEx ()
#38 0x00000000004a1c9a in ?? ()
#39 0x0000000000505f96 in PyObject_Call ()
#40 0x000000000049b07a in PyEval_EvalFrameEx ()
#41 0x00000000004a090c in PyEval_EvalCodeEx ()
#42 0x0000000000499a52 in PyEval_EvalFrameEx ()
#43 0x00000000004a1634 in ?? ()
#44 0x000000000044e4a5 in PyRun_FileExFlags ()
#45 0x000000000044ec9f in PyRun_SimpleFileExFlags ()
#46 0x000000000044f904 in Py_Main ()
#47 0x00007ffff7818ec5 in __libc_start_main (main=0x44f9c2 <main>, argc=2, argv=0x7fffffffde28, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fffffffde18) at libc-start.c:287
#48 0x0000000000578c4e in _start ()

1 个答案:

答案 0 :(得分:1)

打印表达式结果时,IPython的特殊行为是它尝试在对象上调用几个特殊方法以获得不同形式的表示:_repr_pretty__repr_html_,{{1 }} 等等。这些用于在Web浏览器中显示IPython笔记本等内容中的repr,或者将matplotlib图形的输出显示为图像。此逻辑包含在_repr_png_类的IPython.lib.pretty中。

在查找这些特殊方法时,它通过RepresentationPrinter获取结果对象的类,并手动遍历其方法解析顺序,而不是正常调用特殊方法。它这样做是为了找出是否为该类的任何基类注册了任何漂亮的打印机。只有在没有找到特殊方法且没有找到注册的漂亮打印机之后,它才会回到调用__class__

崩溃可能与从对象(repr())获取属性或从对象的类获取属性有关(老实说,我不知道C扩展类型如何支持它。)