Ошибка PyObject при вызове функции

Я пытаюсь использовать 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

Решение

добавлять PySys_SetArgv(argc, argv) (вместе с int argc, char **argv параметры для main), и ваш код будет работать.

tk.Tk() доступ sys.argv, который не существует, если PySys_SetArgv был вызван. Это вызывает исключение, которое распространяется из get_ip и сообщается в Python / C PyObject_CallObject возврате NULL, NULL хранится в result и перешел к PyString_AsString, что является непосредственной причиной наблюдаемой аварии.

Несколько замечаний по коду:

  • Чтобы отладить это, потребовались усилия, потому что код не проверяет ошибки вообще, он слепо нажимает вперед, пока не завершится сбоем из-за передачи указателей NULL. Самое меньшее, что можно сделать, это написать что-то вроде:

    if (!ip_module_name) {
    PyErr_Print();
    exit(1);
    }
    // and so on for every PyObject* that you get from a Python API call
    

    В реальном коде вы бы не exit(), но сделай уборку и вернись NULL (или поднять исключение уровня C ++, или что угодно).

  • Нет необходимости звонить PyGILState_Ensure в теме, которую вы уже знаете, содержит GIL. Как документация PyEval_InitThreads заявляет, что инициализирует GIL и приобретает Это. Вам нужно только повторно получить GIL при вызове в Python из обратного вызова C, который происходит, скажем, из цикла событий набора инструментов, который не имеет ничего общего с Python.

  • Новые ссылки, полученные от Python должны быть Py_DECREF«Один раз больше не нужен. Подсчет ссылок может быть опущен в минимальном примере для краткости, но его всегда следует учитывать.

2

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]