Как перенаправить stderr в Python? Через Python C API? - PullRequest
2 голосов
/ 24 декабря 2009

Это сочетание двух моих недавних вопросов:
[1] Метод экземпляра Python в C
[2] Как перенаправить stderr в Python?

Я бы хотел зарегистрировать вывод stdout и stderr из скрипта python.

Я хочу спросить, создать новый тип в соответствии с [1] довольно сложно. Упрощает ли это вещи, если бы не было необходимости выставлять новый тип в Python, то есть он существовал бы только в C?

Я имею в виду, что когда Python печатает что-то, он идет в «Objects / fileobject.c» и там, в «PyFile_WriteObject», он проверяет, можно ли записать его аргумент:

writer = PyObject_GetAttrString(f, "write");
if (writer == NULL)
...

Также можно получить stdout и stderr следующим образом:

PyObject* out = PySys_GetObject("stdout");
PyObject* err = PySys_GetObject("stderr");

Мой вопрос заключается в том, возможно ли каким-либо образом создать необходимый PyObject, который удовлетворяет вышеуказанному PyObject_GetAttrString (f, "write") 'и может вызываться, поэтому я могу написать:

PySys_SetObject("stdout", <my writer object / class / type / ?>);

http://docs.python.org/c-api/sys.html?highlight=pysys_setobject#PySys_SetObject

Таким образом, не нужно было бы выставлять новый «тип писателя» остальной части скрипта Python, поэтому я подумал, что написать код может быть немного проще ...?

Ответы [ 2 ]

9 голосов
/ 24 декабря 2009

Просто создайте объект модуля (вы делаете это в любом случае, если вы используете C API! -) и сделайте так, чтобы он имел подходящую функцию write - этот объект модуля будет пригоден в качестве второго аргумента для PySys_SetObject.

В своем ответе на другой ваш вопрос я указал вам на xxmodule.c, файл примеров в источниках C Python, который представляет собой модуль с множеством примеров, включая типы и функции различных типов - вы можете работать оттуда даже если (загадочно для меня) вы считаете "сделать новый тип" частью слишком трудным; -).

Редактировать : вот тривиальный рабочий пример (aview.py):

#include "Python.h"
#include <stdio.h>

static PyObject *
aview_write(PyObject *self, PyObject *args)
{
    const char *what;
    if (!PyArg_ParseTuple(args, "s", &what))
        return NULL;
    printf("==%s==", what);
    return Py_BuildValue("");
}

static PyMethodDef a_methods[] = {
    {"write", aview_write, METH_VARARGS, "Write something."},
    {NULL, NULL, 0, NULL}
};

PyMODINIT_FUNC
initaview(void)
{
    PyObject *m = Py_InitModule("aview", a_methods);
    if (m == NULL) return;
    PySys_SetObject("stdout", m);
}

Как только этот aview модуль установлен правильно:

$ python
Python 2.5.4 (r254:67917, Dec 23 2008, 14:57:27) 
[GCC 4.0.1 (Apple Computer, Inc. build 5363)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import aview
>>> print 'ciao'
==ciao====
==>>> 

... любая строка, отправляемая в стандартный вывод, записывается со знаком == вокруг нее (и это print вызывает .write дважды: с 'ciao', а затем снова с новой строкой).

4 голосов
/ 24 сентября 2012

Основываясь на ответе Алекса, здесь полностью рабочий код C, без Python "import aview", в Python 3 (поэтому нет Py_InitModule) и с перенаправлением stderr:

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


PyObject* aview_write(PyObject* self, PyObject* args)
{
    const char *what;
    if (!PyArg_ParseTuple(args, "s", &what))
        return NULL;
    printf("==%s==", what);
    return Py_BuildValue("");
}


PyObject* aview_flush(PyObject* self, PyObject* args)
{
    return Py_BuildValue("");
}


PyMethodDef aview_methods[] =
{
    {"write", aview_write, METH_VARARGS, "doc for write"},
    {"flush", aview_flush, METH_VARARGS, "doc for flush"},
    {0, 0, 0, 0} // sentinel
};


PyModuleDef aview_module =
{
    PyModuleDef_HEAD_INIT, // PyModuleDef_Base m_base;
    "aview",               // const char* m_name;
    "doc for aview",       // const char* m_doc;
    -1,                    // Py_ssize_t m_size;
    aview_methods,        // PyMethodDef *m_methods
    //  inquiry m_reload;  traverseproc m_traverse;  inquiry m_clear;  freefunc m_free;
};

PyMODINIT_FUNC PyInit_aview(void) 
{
    PyObject* m = PyModule_Create(&aview_module);
    PySys_SetObject("stdout", m);
    PySys_SetObject("stderr", m);
    return m;
}


int main()
{
    PyImport_AppendInittab("aview", PyInit_aview);
    Py_Initialize();
    PyImport_ImportModule("aview");

    PyRun_SimpleString("print(\'hello to buffer\')");
    PyRun_SimpleString("make a SyntaxException in stderr");

    Py_Finalize();

    return 0;

}

Обратите внимание, что если вы планируете иметь несколько разных интерпретаторов, этого будет недостаточно, потому что aview_write не сможет узнать, в какой буфер добавить. Вам понадобится что-то вроде , что .

Здесь - это замечательная справка о том, как добавлять новые модули и типы, кстати.

...