中嵌入的Python重定向stdout/stderr,NET应用程序到文本框

b1payxdu  于 2023-04-28  发布在  Python
关注(0)|答案(2)|浏览(143)

我试图在C# Windows窗体应用程序中嵌入一个交互式Python shell,使用Python.NET
我能够将解释器嵌入到我的C#应用程序中,并从访问Python模块。我现在尝试将Python解释器的输出和错误重定向到一个。NET文本框。虽然我能够将标准输出重定向到文件,但我在将输出路由到文本框时遇到了麻烦。
这就是我迄今为止所尝试的:这个想法是分配Python的sys。stdout到a .NET对象,该对象实现与Python流相同的接口(write()、writelines())。..):

.NET类模拟Python流:

public class TextBoxStream : PyObject // To assign to sys.stdout. Is this correct?
{
    private TextBox _output = null;            

    public TextBoxStream() {}

    public TextBoxStream(TextBox output)
    {
        _output = output;
    }

    void write(object value)
    {
        _output.AppendText(value.ToString());
    }

    void writelines(object value)
    {
    }
}

在Form1.cs中:

private void button1_Click(object sender, EventArgs e)
{
    using (Py.GIL())
    {
        // Redirect stdout to text box
        dynamic sys = PythonEngine.ImportModule("sys");
        TextBoxStream textBoxStream = new TextBoxStream(textBox1);
        sys.stdout = textBoxStream;
        //sys.SetAttr("stdout", textBoxStream); // This did not work either
        string code =
            "import sys\n" +
            "print 'Message 1'\n" +
            "sys.stdout.write('Message 2')\n" +
            "sys.stdout.flush()";

        PyObject redirectPyObj = PythonEngine.RunString(code); // NULL
        sys.stdout.write("Message 3"); 
        // Exception thrown: 'Python.Runtime.PyObject' does not contain a definition for 'stdout'
    }
}

这也不起作用:redirectPyObj为NULL。我尝试使用旧的和新的Python。NET API(具有动态)。不是系统。stdout.write也不会将print语句写入文本框。
任何关于如何处理这一问题的想法都将是非常有帮助的。

f87krz0w

f87krz0w1#

一个对我有效的解决方案是将Python的stdout/stderr重定向到Python中的流。然后我就能把这条小溪引到。NET文本框。

private void button1_Click(object sender, EventArgs e)
{
    using (Py.GIL())
    {
        // Redirect stdout to text box
        dynamic sys = PythonEngine.ImportModule("sys");

        string codeToRedirectOutput =
            "import sys\n" +
            "from io import StringIO\n" +
            "sys.stdout = mystdout = StringIO()\n" +
            "sys.stdout.flush()\n" +
            "sys.stderr = mystderr = StringIO()\n" +
            "sys.stderr.flush()\n";
        PythonEngine.RunString(codeToRedirectOutput);            

        // Run Python code
        string pyCode = "print(1 + 2)";
        PyObject result = PythonEngine.RunString(pyCode); // null in case of error
        if (result != null)
        {
            string pyStdout = sys.stdout.getvalue(); // Get stdout
            pyStdout = pyStdout.Replace("\n", "\r\n"); // To support newline for textbox
            textBox1.Text = pyStdout;             
        }
        else
        {
             PythonEngine.PrintError(); // Make Python engine print errors
             string pyStderr = sys.stderr.getvalue(); // Get stderr
             pyStderr = pyStderr.Replace("\n", "\r\n"); // To support newline for textbox
             textBox1.Text = pyStderr;
        }     
    }
}

通过这段代码,我能够将stdout(以及错误情况下的stderr)从Python引擎重定向到。NET文本框。

7ajki6be

7ajki6be2#

Python 3.4引入了contextlib。redirect_stdout()在标准库中。contextlib。redirect_stderr()在Python 3中添加。5.www.example www.example.com
这些上下文管理器允许在Python代码中整洁地重定向stderr和stdout,如下所示:

import contextlib
import sys
import io
...
s = None
# Redirect stderr to stdout
with contextlib.redirect_stderr(sys.stdout):
    # Redirect stdout to a buffer
    with contextlib.redirect_stdout(io.StringIO()) as f:
        ...
        <your code>
        ...
        # Fetch any redirected stdout/stderr messages
        s = f.getvalue()
# Print them or whatever you like
print(s)

Python中也有相同的上下文管理器。Net等价的C#代码是:

dynamic contextLib = Py.Import("contextlib");
dynamic ioLib = Py.Import("io");
dynamic sysLib = Py.Import("sys");
string pyStdOut = null;

Py.With((PyObject) contextLib.redirect_stderr(sysLib.stdout), _ =>
{
    Py.With((PyObject) contextLib.redirect_stdout(ioLib.StringIO()), f =>
    {
        ...
        <your code>
        ...
        pyStdOut = f.getvalue();
    });
});

pyStdOut = pyStdOut.Replace("\n", "\r\n");

相关问题