Home

[icon] 超越无限的blog
View:Recent Entries.
View:Archive.
View:Friends.
View:User Info.
You're looking at the latest 3 entries.

Tags:, ,
Subject:C代码中如何得到python脚本异常时的traceback信息
Time:03:22 am
在软件项目的开发过程中,我们总是试图让程序能够适应更多的应用环境以及业务流程,不管你对于需求的了解如何准确,也不管你做了有多么充分的估计,但有很多情况仍然让你无法应付,比如:需求是会变化的;维护项目的人不一定都能用C/C++写出没有内存问题的代码等等。

让软件系统能够适应更多变化的方法有很多种,高度的抽象、动态链接技术等等都是一直以来被大家采用较广的方法,那么今天我们要讨论的是脚本引擎的嵌入问题。通常我更喜欢c代码加上python脚本引擎的结构,python的好处就不多说了。不过在C中嵌入python脚本引擎调用之后也有一些非常麻烦的地方,比如不便于调试,因为我们的宿主应用程序必然会为python脚本wrap一些module、class、function等等,因此这带来了调试的难度,有时候仅仅依赖print是一件非常低效的事,那么我们如何得到python脚本在异常时的traceback情况呢?比如代码出现异常到底是在哪个脚本文件中,到底是哪行代码出了问题?错误又是什么呢?我们先来看看下面的函数:

#include <Python.h>
#include <compile.h>
#include <frameobject.h>
#include <traceback.h>

void
process_python_exception(void)
{
  char buf[512], *buf_p = buf;
  PyObject *type_obj, *value_obj, *traceback_obj;
  PyErr_Fetch(&type_obj, &value_obj, &traceback_obj);
  if (value_obj == NULL)
    return;

  if (!PyString_Check(value_obj))
    return;

  char *value = PyString_AsString(value_obj);
  size_t szbuf = sizeof(buf);
  int l;
  PyCodeObject *codeobj;

  l = snprintf(buf_p, szbuf, _("Error Message:\n%s"), value);
  buf_p += l;
  szbuf -= l;

  if (traceback_obj != NULL) {
    l = snprintf(buf_p, szbuf, _("\n\nTraceback:\n"));
    buf_p += l;
    szbuf -= l;

    PyTracebackObject *traceback = (PyTracebackObject *)traceback_obj;
    for (;traceback && szbuf > 0; traceback = traceback->tb_next) {
      codeobj = traceback->tb_frame->f_code;
      l = snprintf(buf_p, szbuf, "%s: %s(# %d)\n",
                   PyString_AsString(codeobj->co_name),
                   PyString_AsString(codeobj->co_filename),
                   traceback->tb_lineno);
      buf_p += l;
      szbuf -= l;
    }
  }

  message_error_dialog_show(buf);

  Py_XDECREF(type_obj);
  Py_XDECREF(value_obj);
  Py_XDECREF(traceback_obj);
}

PyErr_Fetch用来获取异常对象,并且同时可以得到traceback对象,traceback其实是一个PyTracebackObject结构体,可以在python的头文件traceback.h中找到,PyTracebackObject其实也是一个单向链表,可以通过其tb_next成员来枚举,其tb_frame则是一个_frame结构体,在frameobject.h头文件中可以看到,其中f_code就是我们需要的PyCodeObject结构体,PyCodeObject中就可以得到co_name和co_filename这两个关键的描述,一个是错误信息另一个是文件名称,PyTracebackObject的tb_lineno就是出错的行号,有了这些数据我们调试还有困难吗?
comments: Leave a comment Add to Memories Tell a Friend

Tags:, ,
Subject:python嵌入与扩展的入门级FAQ
Time:12:00 am
以下是我在开发一个应用中集成python脚本引擎的过程中所遇到的一些入门级问题,稍后再整理一些比较完整的关于python扩展与嵌入的日志。

1、如何在宿主应用中注册module?可在Py_Initialize之前调用PyImport_AppendInittab来注册,也可在Py_Initialize之后直接调用注册函数。

2、如何添加宿主应用脚本的路径到python搜索路径?在Py_Initialize之后通过PySys_GetObject("path")得到sys.path,然后再通过PyList_Insert加入宿主应用的脚本路径。

3、如何调用python模块中的函数?通过PyImport_ImportModule得到module,然后再通过PyModule_GetDict从module中得到dict,再通过PyDict_GetItemString得到函数对象,最后通过PyObject_CallObject或其它PyObject_Call系列函数调用,当然调用之前最好用PyCallable_Check检查,另外就是dict、func都属于Borrowed reference,因此不需要Py_DECREF或Py_XDECREF。

4、所有的wrapper函数都应该返回PyObject实例指针,即使在python中调用的时候并不需要返回值,但仍需要返回Py_None,相当于C/C++中的void,Py_INCREF(Py_None); return Py_None;当然也可以用宏Py_RETURN_NONE来代替。
comments: Leave a comment Add to Memories Tell a Friend

Tags:, , ,
Subject:gtk+开发中的几个小经验
Time:11:09 pm
1、在gtk+开发过程中,我们经常需要在event handler中来访问该窗口中的某些控件的信息,通常习惯于整一大堆全局变量,其实还有更好的方式,在glib的实现中我们可以通过g_object_set_data和g_object_get_data给一个GObject对象绑定自定义的数据及属性,g_object_set_data_full还可以在对象释放资源时通知你的回调函数来做资源释放处理,这样我们就可以给event handler传递一个窗口对象指针就行了,其它的数据及控件信息可以通过窗口对象得到我们想要的东西。

2、某些对象并未提供所有属性的存取方法,但只要是通过GObject继承下来的对象均可采用g_object_set、 g_object_set_property及g_object_get、g_object_get_property来存取这些属性,如给 TreeView中某一列的值要求居右则可以对gtk_cell_renderer_text_new()产生的GtkCellRenderer对象调用 g_object_set(renderer, "xalign", 1.0, NULL)来达到居右的效果。

3、使用g_idle_add及g_timeout_add等函数中的时候一定要小心,由于代码延后执行,因此一定要保证其数据的生命周期,如下面的例子是我在开发一个项目应用中遇到的问题(注释掉的代码即为出现问题之后的修正代码),传递的Python对象到代码执行的时候已经被释放掉了,因此出现了比较奇怪的现象:如果连续调用这个函数两次,结果加进去的两行信息全部都是最后一次的数据,当然可能还会有更奇特的现象发生。
Read more... )
comments: Leave a comment Add to Memories Tell a Friend

Advertisement

[icon] 超越无限的blog
View:Recent Entries.
View:Archive.
View:Friends.
View:User Info.
You're looking at the latest 3 entries.