Eci*_*irH 2 c python stdout python-c-api io-redirection
这是我最近两个问题的组合:
[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)
...
Run Code Online (Sandbox Code Playgroud)
此外,有可能像这样得到stdout和stderr:
PyObject* out = PySys_GetObject("stdout");
PyObject* err = PySys_GetObject("stderr");
Run Code Online (Sandbox Code Playgroud)
我的问题是,是否有可能构造必要的PyObject,它满足上面的'PyObject_GetAttrString(f,"write")'并且可以调用,所以我可以写:
PySys_SetObject("stdout", <my writer object / class / type / ?>);
Run Code Online (Sandbox Code Playgroud)
http://docs.python.org/c-api/sys.html?highlight=pysys_setobject#PySys_SetObject
这样,就没有必要将新的"writer类型"暴露给Python脚本的其余部分,所以我认为编写代码可能有点简单......?
只需创建一个模块对象(无论如何,如果你正在使用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);
}
Run Code Online (Sandbox Code Playgroud)
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====
==>>>
Run Code Online (Sandbox Code Playgroud)
...发送到标准输出的任何字符串都会==在其周围写上符号(这会print调用.write两次:with 'ciao',然后再使用换行符).
根据Alex的回答,这是完全可用的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;
}
Run Code Online (Sandbox Code Playgroud)
但是请注意,如果您打算有几个不同的解释器,这将是不够的,因为aview_write将无法知道要追加到哪个缓冲区。你需要像这样的东西。
这是有关如何添加新模块和类型的出色参考,顺便说一句。