函数调用上的PyObject段错误

时间:2013-04-25 06:01:50

标签: c++ python-2.7 tkinter python-c-api

我正在尝试使用Python打开一个对话框来接受我的C ++应用程序的输入。

这是我想要做的非常小的代表:

#include <iostream>
#include <Python.h>

int main()
{
    /* Begin Python Ititialization - only needs to be done once. */
    PyObject *ip_module_name = NULL;
    PyObject *ip_module = NULL;
    PyObject *ip_module_contents = NULL;
    PyObject *ip_module_getip_func = NULL;

    Py_Initialize();
    PyEval_InitThreads();

    ip_module_name     = PyString_FromString( "get_ip" );
    ip_module          = PyImport_Import( ip_module_name );
    ip_module_contents = PyModule_GetDict( ip_module );
    ip_module_getip_func = PyDict_GetItemString( ip_module_contents, "get_ip_address" );
    /* End Initialization */

    PyGILState_STATE state = PyGILState_Ensure();
    PyObject *result = PyObject_CallObject( ip_module_getip_func, NULL );

    if( result == Py_None )
        printf( "None\n" );
    else
        printf( "%s\n", PyString_AsString( result ) );

    PyGILState_Release( state );

    /* This is called when the progam exits. */
    Py_Finalize();
}

但是,当我用PyObject_CallObject调用该函数时,应用程序会出现段错误。我猜这是因为我正在使用Tk库。我已经尝试将我的应用程序与_tkinter.lib,tk85.lib,tcl85.lib,tkstub85.lib,tclstub85.lib相关联,并且没有任何帮助。我很难过......

这是脚本:

import Tkinter as tk
from tkSimpleDialog import askstring
from tkMessageBox import showerror

def get_ip_address():

    root = tk.Tk()
    root.withdraw()

    ip = askstring( 'Server Address', 'Enter IP:' )

    if ip is None:
        return None

    ip = ip.strip()

    if ip is '':
        showerror( 'Error', 'Please enter a valid IP address' )
        return get_ip_address()

    if len(ip.split(".")) is not 4:
        showerror( 'Error', 'Please enter a valid IP address' )
        return get_ip_address()

    for octlet in ip.split("."):
        x = 0

        if octlet.isdigit():
            x = int(octlet)
        else:
            showerror( 'Error', 'Please enter a valid IP address' )
            return get_ip_address()

        if not ( x < 256 and x >= 0 ):
            showerror( 'Error', 'Please enter a valid IP address' )
            return get_ip_address()

    return ip

编辑:添加了我的线程设置

1 个答案:

答案 0 :(得分:3)

PySys_SetArgv(argc, argv)(以及int argc, char **argv参数添加到main),您的代码就可以使用。

tk.Tk()访问sys.argv,除非已调用PySys_SetArgv,否则该get_ip不存在。这会导致异常从PyObject_CallObject传播出来并通过NULL返回NULL报告给Python / C. result会存储到PyString_AsString并传递给if (!ip_module_name) { PyErr_Print(); exit(1); } // and so on for every PyObject* that you get from a Python API call ,这是观察到的崩溃的直接原因。

关于代码的几点评论:

  • 由于代码没有进行任何错误检查,所以需要花费很多工作来调试它,它会盲目地向前按,直到它因为传递NULL指针而崩溃。至少可以做的是写:

    exit()

    在实际代码中,你不会NULL,而是做一些清理并返回PyGILState_Ensure(或者提出一个C ++级别的异常,或任何合适的异常)。

  • 无需在您已知的线程中调用Py_DECREF保存GIL。作为documentation of PyEval_InitThreads状态,它初始化GIL并获取它。从C语言回调调用Python时,您只需要重新获取GIL,这些回调来自与Python无关的工具箱事件循环。

  • 一旦不再需要,从Python收到的新引用需要{{1}}。为简洁起见,最小例子中可能省略了引用计数,但应始终注意它。