C#/.NET通过Python.NET调用Python脚本与本地环境集成

Jasper
Jasper
发布时间:2026-10-15| 6人浏览过
原创

在Windows环境下开发应用时,结合C#强大的UI能力与Python丰富的AI及数据科学库是常见需求。本文介绍如何使用pythonnet(Python.NET)在.NET 6中无缝调用Python代码,包括本地环境封装、第三方库支持、对象交互及性能优化。

方案选择与环境准备

在.NET中调用Python主要有四种方式,pythonnet因兼具高交互性、支持第三方库且无需终端用户安装Python环境,成为成熟软件的首选方案。

方式优点缺点
IronPython无需安装Python环境,无缝集成不支持numpy等主流科学计算库
C++动态链接库交互性强实现复杂,需用户配置Python环境
命令行调用实现简单交互性差,需用户配置环境
打包为EXE无Python依赖体积大,数据传递复杂,性能损失大

以下步骤均在.NET 6环境下测试通过。首先确保已安装Python环境(建议Anaconda),并使用Nuget添加pythonnet引用。

第1步:配置运行环境与路径

核心在于初始化PythonEngine并指向具体的Python DLL及模块路径。为避免用户配置困扰,应将Python虚拟环境随程序分发。

string pathToVirtualEnv = ".\\envs\\pythonnetTest";
// 指定Python版本对应的dll,如python39.dll对应Python 3.9
Runtime.PythonDLL = Path.Combine(pathToVirtualEnv, "python39.dll");
PythonEngine.PythonHome = Path.Combine(pathToVirtualEnv, "python.exe");
// 设置Python模块搜索路径,site-packages必须放在最后以确保优先加载
PythonEngine.PythonPath = $"{pathToVirtualEnv}\\Lib\\site-packages;{pathToVirtualEnv}\\Lib";
PythonEngine.Initialize();

第2步:执行Python脚本与函数调用

所有Python代码执行必须包裹在using (Py.GIL())块内以获取全局解释器锁(GIL)。Python对象推荐使用dynamic类型以简化语法。

// 调用无参方法
dynamic test = Py.Import("test");
test.hello();

// 调用有参并获取返回值
dynamic result = test.add(1, 2);
Console.WriteLine(result);

对应的Python脚本test.py需位于PythonEngine.PythonPath指定的目录下:

def hello():
    print("hello")

def add(a, b):
    return a + b

第3步:集成Anaconda虚拟环境与第三方库

利用Anaconda构建专用虚拟环境可解决复杂的依赖问题:

  1. 创建环境:conda create --prefix=F:\\condaenv\\env_name python=3.7
  2. 激活环境:conda activate F:\\condaenv\\env_name
  3. 安装库:pip install numpy

在C#中直接调用NumPy示例:

using (Py.GIL())
{
    dynamic np = Py.Import("numpy");
    // 注意:数学运算时Python变量需在左侧,如np.pi * 2,而非 2 * np.pi
    Console.WriteLine(np.cos(np.pi * 2));

    dynamic sin = np.sin;
    Console.WriteLine(sin(5));
    double c = (double)(np.cos(5) + sin(5));

    // 数组操作
    dynamic a = np.array(new List<float> { 1, 2, 3 });
    dynamic b = np.array(new List<float> { 6, 5, 4 }, dtype: np.int32);
    Console.WriteLine(a * b);
}

若未正确绑定或环境缺失,将无法导入模块。请确认PythonPath准确指向虚拟环境的Lib/site-packages目录。

第4步:C#对象与Python双向传递

通过ToPython()方法可将C#对象传入Python。需先在C#中定义类结构:

public class Person {
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

在调用时将实例转换为Python对象:

Person p = new Person("John", "Smith");
dynamic pyPerson = p.ToPython();
string fullName = test.FullName(pyPerson); // 调用test.py中的FullName方法

Python侧接收后即可访问属性:

def FullName(p):
    return p.FirstName + " " + p.LastName

第5步:加密与性能优化(PyD文件)

将Python源码编译为pyd(Windows下的C扩展模块)可实现代码保护并提升执行效率。步骤如下:

  1. 安装编译工具:pip install cython
  2. 创建setup.py:
    from distutils.core import setup
    from Cython.Build import cythonize
    setup(name="testName", ext_modules=cythonize("test.py"))
  3. 执行编译:python setup.py build_ext --inplace
编译后生成的文件通常名为test.cpXX-win_amd64.pyd,可直接重命名为test.pyd供pythonnet调用,效果等同于正常导入但不可逆向查看源码。

执行速度对比分析

通过对比耗时循环任务,验证不同调用方式的性能差异:

  • 原生Python执行:test.py独立运行。
  • C#调用Python:通过pythonnet托管入口调用。
  • C#调用PyD:通过编译后的pyd文件调用。

测试结果参考图示:

数据显示,使用pythonnet会引入少量的跨语言调用开销,但在常规业务逻辑中影响可控;而调用pyd文件由于减少了部分解析层,执行速度甚至优于直接调用纯Python脚本,兼顾了安全性与性能。

以上就是C#/.NET程序调用Python的教程分享的详细内容,更多关于C#调用Python的资料请关注本站其它相关文章!

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。