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

Redirect stdout/stderr from Python embedded in .NET application to text box

我正在尝试使用 Python.NET.

在 C# Windows Forms 应用程序中嵌入交互式 Python shell

我能够将解释器嵌入我的 C# 应用程序并从 .NET 访问 Python 模块。我现在正在尝试将 Python 解释器的输出和错误重定向到 .NET 文本框。虽然我能够将标准输出重定向到一个文件,但我在将输出路由到文本框时遇到了问题。

这是我目前尝试过的: 想法是将 Python 的 sys.stdout 分配给一个 .NET 对象,该对象实现与 python 流相同的接口(write()、writelines()...):

.NET class 模仿 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 (动态)。 sys.stdout.write 和 print 语句都不会写入文本框。

关于如何解决这个问题的任何想法都会非常有帮助。

对我有用的解决方案是将 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;
        }     
    }
}

使用此代码,我能够将 Python 引擎的 stdout(和错误情况下的 stderr)重定向到 .NET 文本框。