4

これは私の最近の 2 つの質問の組み合わせです:
[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そのモジュール オブジェクトは、 の 2 番目の引数として適切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====
==>>> 

...標準出力に出力される文字列は、==記号で囲まれて書き込まれます (これは で2 回print呼び出され、次に改行で再度呼び出されます)。.write'ciao'

于 2009-12-24T02:51:44.917 に答える
7

Alexの回答に基づいて、Pythonの「importaview」を使用せず、Python 3(Py_InitModuleを使用しない)で、stderrリダイレクトを使用して完全に機能するCコードを次に示します。

#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 に答える