用 process 启动 python 脚本最稳:需显式指定 python.exe 完整路径、设 useshellexecute=false 和 createnowindow=true、统一 utf-8 编码、通过 stdout 输出 json 结构化数据、设置 waitforexit 超时、用 argumentlist 传参防注入,并确保 python 环境含所需依赖。

用 Process 启动 Python 脚本最稳,别碰 IronPython
直接调用系统 Python 解释器是最可靠的方式。IronPython 兼容性差、不支持 NumPy/TensorFlow 等 C 扩展,且已多年未更新,实际项目中基本不可用。
常见错误现象:System.ComponentModel.Win32Exception: 系统找不到指定的文件——多半是没配好 python.exe 路径或环境变量;UnicodeDecodeError 则常因控制台编码和 C# 默认编码不一致导致。
- 显式指定完整路径,比如
C:Python39python.exe,避免依赖PATH(尤其在 Windows 服务或 IIS 中) - 设置
StartInfo.UseShellExecute = false,否则无法重定向标准输出 - 务必设
StartInfo.CreateNoWindow = true,防止弹黑窗(尤其 GUI 应用) - 用
StartInfo.StandardOutputEncoding = Encoding.UTF8统一编码,Python 脚本开头加# -*- coding: utf-8 -*-
Python 脚本必须用 print() 输出结果,别 return
C# 拿不到 Python 函数的 return 值,只能读取 stdout。这是进程间通信的本质限制,不是 bug。
使用场景:脚本做数据预处理、调用模型推理、生成报告等,只要最终结果能序列化为字符串就行(JSON 最稳妥)。
- Python 端用
json.dumps()输出结构化数据,C# 用JsonSerializer.Deserialize<t>()</t>解析 - 避免 print 多余空行或调试信息,否则会污染 JSON 格式;可用
sys.stdout.flush()确保立即输出 - 如需错误反馈,把异常信息也 print 到 stdout,再由 C# 判断是否含
"error"字段,而不是只依赖 stderr(容易丢失)
Process.WaitForExit() 必须加超时,否则可能卡死
Python 脚本如果陷入死循环、等待用户输入、或加载大模型卡住,C# 进程就会无限等待,UI 冻结或 API 请求超时。
性能影响:不设超时的阻塞调用会让整个线程挂起,对 ASP.NET Core 或 WinForms 都是硬伤。
- 始终用
WaitForExit(30000)(单位毫秒),30 秒对多数脚本足够,太短易误判失败 - 退出后检查
Process.ExitCode:0 表示正常结束,非 0 通常代表异常(但 Python 不一定严格遵守,所以仍要解析 stdout) - 如果超时,立刻调用
Process.Kill(),并注意释放资源(Process.Dispose())
传参别拼字符串,用 StartInfo.ArgumentList(.NET 5+)
老写法 StartInfo.Arguments = $"script.py {inputPath} {outputPath}" 有严重安全风险:路径含空格、引号、反斜杠时必然崩,还会被注入恶意参数。
兼容性影响:.NET Core 3.1 不支持 ArgumentList,得降级用 Arguments + 手动转义(推荐用 string.Join(" ", args.Select(a => $""{a.Replace(""", "\"")}"")))
- .NET 5 及以上:直接用
StartInfo.ArgumentList.Add("script.py"); StartInfo.ArgumentList.Add(inputPath); ... - Python 端用
sys.argv[1:]接收,天然规避 shell 解析问题 - 敏感内容(如 token、密码)不要走命令行,改用临时文件 + 文件路径传参,或 stdin 输入
事情说清了就结束。最麻烦的其实是 Python 环境隔离和依赖管理——C# 进程看不到 venv 的 pip 包,得确保调用的是带完整 site-packages 的 python.exe。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











