C#如何调用Python脚本_C#执行py文件并获取返回结果【跨语言】
用 Process 拉起 Python 解释器,是跨语言调用中最稳妥的路径。没什么花哨,就是老老实实启动一个 python.exe 进程,通过标准输入输出管道通信。关键点有几个:python.exe 路径得对,最好指定绝对路径;脚本也建议用绝对路径,免得工作目录搞鬼;别忘了把 UseShellExe
用 Process 拉起 Python 解释器,是跨语言调用中最稳妥的路径。没什么花哨,就是老老实实启动一个 python.exe 进程,通过标准输入输出管道通信。关键点有几个:python.exe 路径得对,最好指定绝对路径;脚本也建议用绝对路径,免得工作目录搞鬼;别忘了把 UseShellExecute 设为 false,不然重定向 IO 就没戏了;参数拼进 Arguments 字符串,别塞到 FileName 里。另外,加个 -u 参数能强制 Python 无缓冲输出,输入输出统一用 JSON 格式最省心。超时、读 stderr、检查 ExitCode——这三样少一个,线上就可能出幺蛾子。

用 Process 启动 Python 解释器是最直接的方式
别走弯路——Assembly.LoadFrom 或者 IronPython 那种内嵌解析器的玩法,除非你有特殊理由,否则绝大多数场景下,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 时加
-u参数强制无缓冲:python.exe -u script.py - Python 脚本里手动加
print(..., flush=True) - 结果尽量用 JSON 格式输出,方便 C# 解析,别用多行乱序的 print 文本
- 脚本末尾不要留
input()交互式语句,否则进程卡死等用户输入
示例 Python 脚本(calc.py):
import json
import sys
# 解析命令行参数(简单起见,只取第一个)
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"}
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解析() - 临时文件路径注意权限和清理(尤其多线程并发时),优先走 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——问题一定在半夜出现。


































