Pergunta

Esta é uma combinação das minhas duas perguntas recentes:
[1] Método da instância do Python em C
[2] Como redirecionar o Stderr em Python?

Eu gostaria de registrar a saída do stdout e do Stderr a partir de um script python.

O que eu quero perguntar é que criar um novo tipo de acordo com [1] parece bastante complicado. Isso simplifica as coisas se não houvesse necessidade de expor o novo tipo ao Python, ou seja, ele existiria apenas em C?

Quero dizer, quando o Python imprime algo, para "Objetos/FileObject.c" e lá em "pyfile_writeoBject", verifique se é possível escrever em seu argumento:

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

Além disso, é possível obter stdout e stderr assim:

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

Minha pergunta é então, de alguma forma é possível construir o PyObject necessário que satisfaz o 'pyobject_getattring acima (f, "write") e é chamável para que eu possa escrever:

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

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

Dessa forma, não haveria necessidade de expor o novo "tipo de escritor" ao restante do script Python, então pensei que seria um pouco mais simples escrever o código ...?

Foi útil?

Solução

Basta fazer um objeto de módulo (você está fazendo isso de qualquer maneira, se você está usando a API C!-) e faça com que ele tenha um adequado write função - esse objeto do módulo será adequado como o segundo argumento para PySys_SetObject.

Na minha resposta à sua outra pergunta, apontei você para xxmodule.c, um exemplo de arquivo nas fontes C do Python, que é um módulo com muitos exemplos, incluindo tipos e funções de vários tipos - você pode trabalhar a partir daí, mesmo que (misteriosamente para mim) considera a parte "fazer um novo tipo" difícil;-).

Editar: Aqui está um exemplo de trabalho trivial (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);
}

Uma vez que isso aview O módulo está instalado corretamente:

$ 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====
==>>> 

... qualquer string emitida para saída padrão é escrita com == sinais em torno dele (e isso print chamadas .write duas vezes: com 'ciao', e, novamente, com uma nova linha).

Outras dicas

Com base na resposta de Alex, aqui está o código C totalmente funcionando, sem o Python "Import aview", no Python 3 (então não py_initmodule) e com redirecionamento do 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;

}

Observe, porém, que se você planeja ter vários intérpretes distintos, isso não será suficiente, porque aview_write Não será capaz de saber em qual buffer anexar. Você precisará de algo como este.

Aqui é uma referência incrível sobre como adicionar novos módulos e tipos, btw.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top