4

这是我最近的两个问题的组合:
[1] C 中的 Python 实例方法
[2]如何在 Python 中重定向 stderr?

我想从 python 脚本记录 stdout 和 stderr 的输出。

我想问的是,根据 [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_GetAttrString(f,“write”)'并且可以调用的必要PyObject,以便我可以编写:

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

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

这样,就不需要将新的“编写器类型”暴露给 Python 脚本的其余部分,所以我认为编写代码可能会更简单一些......?

4

2 回答 2

12

只需创建一个模块对象(无论如何,如果您使用 C API!-)并使其具有合适的write功能 - 该模块对象将适合作为PySys_SetObject.

在我对你的另一个问题的回答中,我指出xxmodule.c了 Python 的 C 源代码中的一个示例文件,它是一个包含很多示例的模块,包括各种类型和函数——即使(对我来说很神秘)你也可以从那里工作您认为“制作新类型”部分太难了;-)。

编辑:这是一个简单的工作示例(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',然后再次使用换行符)。

于 2009-12-24T02:51:44.917 回答
7

根据亚历克斯的回答,这里是完全工作的 C 代码,没有 Python 的“导入视图”,在 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无法知道要附加到哪个缓冲区。你会需要这样的东西

是一个关于如何添加新模块和类型的很棒的参考,顺便说一句。

于 2012-09-24T10:25:39.573 回答