Process启动Python解释器是最直接稳定的方式,需指定python.exe路径、用绝对路径调用脚本、设置UseShellExecute=false并重定向IO,加-u参数避免缓冲,输入输出推荐JSON格式,务必设超时、读stderr、检查ExitCode。

用 Process 启动 Python 解释器是最直接的方式
不要试图用 Assembly.LoadFrom 或 IronPython(除非你明确需要在 .NET 运行时内嵌 Python 解析器),绝大多数跨语言调用场景下,Process 是最稳定、兼容性最好、调试最直观的选择。它本质是启动一个独立的 python.exe 进程执行脚本,C# 通过标准输入/输出管道与其通信。
关键点:
-
python.exe必须在系统 PATH 中,或你指定完整路径(比如C:\Python39\python.exe) - 脚本路径建议用绝对路径,避免工作目录不一致导致
FileNotFoundError - 务必设置
UseShellExecute = false,否则无法重定向 stdin/stdout - 如果 Python 脚本有参数,全部拼进
Arguments字符串,不要塞进FileName
var startInfo = new ProcessStartInfo
{
FileName = "python.exe",
Arguments = $"\"{scriptPath}\" --input data.json",
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true,
CreateNoWindow = true
};
using var proc = Process.Start(startInfo);
string output = proc.StandardOutput.ReadToEnd();
string error = proc.StandardError.ReadToEnd();
proc.WaitForExit();
if (proc.ExitCode != 0) throw new InvalidOperationException($"Python failed: {error}");
Python 脚本必须显式输出结果,且避免缓冲干扰
C# 读不到返回值,十有八九是 Python 端没真正“吐出来”。Python 默认对 stdout 做行缓冲(遇到换行才刷出),而子进程模式下可能完全不缓冲或全缓冲,导致 C# 一直 ReadToEnd() 阻塞或读到空字符串。
解决办法:
立即学习“Python免费学习笔记(深入)”;
- 启动 Python 时加
-u参数强制无缓冲:python.exe -u script.py - Python 脚本里手动
print(..., flush=True) - 结果尽量用 JSON 格式输出(方便 C# 解析),别用 print 多行乱序文本
- 避免脚本末尾有交互式输入(如
input()),否则会卡住等待用户输入
示例 Python 脚本(calc.py):
import json
import sys
<h1>解析命令行参数(简单起见,只取第一个)</h1><p>if len(sys.argv) > 1:
try:
x = float(sys.argv[1])
result = {"status": "success", "value": x ** 2}
except Exception as e:
result = {"status": "error", "message": str(e)}
else:
result = {"status": "error", "message": "missing arg"}</p><p>print(json.dumps(result), flush=True)
传参和接收结果推荐 JSON,别用空格分隔字符串
用空格或制表符分隔参数,遇到含空格的路径、JSON 字符串、用户输入内容就立刻崩溃。C# 拼接 Arguments 字符串时容易漏转义,Python 端 sys.argv 解析也脆弱。
更健壮的做法:
- 把所有输入数据序列化成 JSON 字符串,写入临时文件或通过 stdin 传入
- Python 脚本从
sys.stdin读取并解析 - 输出也统一用 JSON,C# 用
System.Text.Json.JsonSerializer.Deserialize<T>()解析 - 临时文件路径注意权限和清理(尤其多线程并发时),优先走 stdin/stdout
C# 端发送 JSON 输入示例:
var inputJson = JsonSerializer.Serialize(new { a = 5.5, b = "test" });
startInfo.RedirectStandardInput = true;
using var proc = Process.Start(startInfo);
using var writer = proc.StandardInput;
writer.WriteLine(inputJson); // 注意换行,Python 的 input() 或 sys.stdin.readline() 依赖它
writer.Close();
超时、异常、编码这三处最容易掉坑
没设超时,Python 脚本死循环或卡住,整个 C# 线程就挂了;中文乱码是因为 Python 默认用系统编码(如 GBK),而 C# Process 默认用 UTF-8;捕获不到异常则错误信息全丢进黑洞。
实操要点:
- 一定要调用
WaitForExit(milliseconds),而不是无参版;超时后主动Kill() - 设置
startInfo.StandardOutputEncoding = Encoding.UTF8和StandardErrorEncoding,并确保 Python 脚本也用 UTF-8 输出(print(..., flush=True)在 UTF-8 环境下默认正常) - 错误流(
StandardError)必须读,否则进程可能因 stderr 缓冲满而僵死 - Linux/macOS 下命令是
python3而非python,跨平台部署需判断环境
真正上线时,这些不是可选项,是必填项。尤其是 stderr 不读、不设超时、不检查 ExitCode,问题一定在半夜出现。


















