C# 如何调用python,避免重复造轮子

news/2025/1/12 1:11:16/

文章目录

  • 原因
  • 资源
  • 调用python文件
    • 需求
    • 解决方案
      • 1、C#里面运行python
      • 引入python文件,再调用其中的方法
      • 启动python脚本,监听返回值
        • 改造一下,可以入参的python调用
        • 查看是否等待python运行完成之后再运行C#
        • 如果参数比较复杂
      • 开一个python网络后端
  • 总结

原因

最近有个需求,需要按照填入的参数动态地生成对应word文件。excel文件我还有办法,word文件我是真没办法。我去.NET上面搜了一下C#支持的word编辑库,发现好像就NPOI支持word文件修改。我没办法网上所了好久,终于找到了对应的博客通过反射和泛型去解决模板化的文件填充。然后领导又给了我一个需求。

现在是能够用占位符去替换了,内容是动态的,现在个数也要动态的。比如我一个报表,有A,B,C三项内容,现在能把ABC三项填进去了。现在的需求是有多个ABC,1,5,10,20个。就是只有一个模板但是能自我复制。自己造轮子太麻烦了。

我后来看到python处理这些特别简单,后来我决定,C#去调用python,不重复造轮子。

Tips:我最后在ChatGPT上面找到方法了,国内C#相关的博客也太少了

Tips:我后来发现nuget上面有minWord和minExcel,专门用于模版文件导入导出,我到时候看一下

资源

这个是自己纯手撸了一个代码
C# 生成word文档(NPOI.XWPF)
这个是我网上逛github逛到的
C# MiniWord Gtihub官网
这个是这个作者另一个快速Excel文件,我感觉这个好像很好使
C# MiniExcel Gtihub官网

python的方法
Python docxtpl 操作 Word 模板文档

调用python文件

需求

如果我们要调用python代码或者文件,我们至少要做的一下几步:

主要要求

  • 能执行。至少我能运行python文件
  • 有返回。我能知道结果。
  • 能入参。我能将参数添加进去
  • 能同步。我能等待python运行完了之后再接着运行C#代码。

保证了这个我们就能勉强使用

次要要求

  • 宽松环境。我python版本、C#和.NET 版本都随意。我能随意pip install 任意版本的第三方库
  • 好部署:在一个新环境下面好部署。最好文件复制过去就能用。
  • 编写简单。我能很快的编写代码
  • 高效。保证一定的运行效率
  • 稳定。不容易出bug

解决方案

c#调用python的三种方法

1、C#里面运行python

太蠢了,我就直接写了

使用Pythonnet库:
Pythonnet是一个开源项目,可以直接在C#中调用Python。首先,需要在C#项目中安装Pythonnet库。可以使用NuGet包管理器或手动安装。

using System;
using Python.Runtime;class Program
{static void Main(){using (Py.GIL()) // 获取全局解释器锁{dynamic py = Py.Import("module_name"); // 导入Python模块// 调用Python函数或访问Python对象dynamic result = py.FunctionName(param1, param2, ...);Console.WriteLine(result);}}
}

引入python文件,再调用其中的方法

C#使用IronPython调用Python

这个要安装Nuget第三方库。
在这里插入图片描述

这个只能说勉强能用,凑合。因为他限定死了python的版本是3.4。你pip装的第三方库都要是能支持python3.4的。而且你的编译环境要和别的python环境隔离。

但是我们知道python所有版本都是有有效期的,好像是5~10年吧,过了有效期就不支持了。现在最新版的python已经是3.11了。

启动python脚本,监听返回值

这个我网上搜半天没找到,最后在chatGPT上面解决了。

using System;
using System.Diagnostics;class Program
{static void Main(){// 创建一个新的ProcessStartInfo对象ProcessStartInfo start = new ProcessStartInfo();// 设置Python解释器路径start.FileName = "path_to_python_interpreter";// 设置要执行的Python脚本路径及其参数(如果有的话)start.Arguments = "path_to_python_script.py arg1 arg2 arg3";// 设置为重定向输入和输出start.UseShellExecute = false;start.RedirectStandardOutput = true;start.RedirectStandardError = true;// 启动进程using (Process process = Process.Start(start)){// 读取标准输出和错误输出string output = process.StandardOutput.ReadToEnd();string error = process.StandardError.ReadToEnd();// 等待进程结束process.WaitForExit();// 输出结果Console.WriteLine("Output:");Console.WriteLine(output);Console.WriteLine("Error:");Console.WriteLine(error);}}
}

按照这个,我们可以创建一个新的文件,然后直接命名行执行,监听返回值。

改造一下,可以入参的python调用

在这里插入图片描述

在这里插入图片描述

import argparse
import timeparser = argparse.ArgumentParser(description='manual to this script')
# 这个是我们输入的两个参数
parser.add_argument("--name", type=str, default="0", help='input name')
parser.add_argument("--age", type=int, default=32,help='input total age')
args = parser.parse_args()print(args.name)
print(args.age)

主函数

using C_python.Utils;
using System.Diagnostics;namespace C_python
{internal class Program{static void Main(string[] args){ProcessStartInfo start = new ProcessStartInfo();// 设置Python解释器路径start.FileName = "python";// 设置要执行的Python脚本路径及其参数(如果有的话)start.Arguments = @"PythonFiles/test.py --name '哈哈哈' --age 849";// 设置为重定向输入和输出start.UseShellExecute = false;start.RedirectStandardOutput = true;start.RedirectStandardError = true;// 启动进程using (Process process = Process.Start(start)){// 读取标准输出和错误输出string output = process.StandardOutput.ReadToEnd();string error = process.StandardError.ReadToEnd();// 等待进程结束process.WaitForExit();// 输出结果Console.WriteLine("Output:");Console.WriteLine(output);Console.WriteLine("Error:");Console.WriteLine(error);}Console.WriteLine("运行完毕");Console.ReadLine();}}
}

运行结果

在这里插入图片描述

查看是否等待python运行完成之后再运行C#

添加休眠


import argparse
import timeparser = argparse.ArgumentParser(description='manual to this script')
# 这个是我们输入的两个参数
parser.add_argument("--name", type=str, default="0", help='input name')
parser.add_argument("--age", type=int, default=32,help='input total age')
args = parser.parse_args()print('我休眠1s')
time.sleep(1)print('我再休眠1s')
time.sleep(1)print(args.name)
print(args.age)

在这里插入图片描述

Tips:我发现python文件选择始终复制不一定能每次修改都复制,还是得进debug文件里面改

如果参数比较复杂

我们不一定会用这么简单的参数,我们后面可能会输入上百行的复杂参数,用命令行就不一定好用了。

所有我们可以将参数写到一个文件里面,每次执行让python去读这个文件里面的数据。简单参数直接传,复杂参数存文件。自己去解析。

开一个python网络后端

理论上是可以的,想调用python功能直接往端口传数据就行了,但是感觉有点大炮打蚊子,没必要。python就是个辅助工具,能用就行。

总结

python有很多很好用的工具,如果我们编程的时候能很方便的调用python的工具帮我们做事情,可以减少很多不必要的麻烦,不用重复造轮子,快速开发,也能顺便学一下python。

当然,也可以在nuget上找对应的第三方库或者手撸一个工具。前者找起来很麻烦,要找好几天,而且尝试好不好用也很麻烦。后者更费时间,简单事情就不要重复地造轮子。我们编程序永远是需求为第一导向,能快速地解决是最好的。


http://www.ppmy.cn/news/724289.html

相关文章

catia V5R21 32位打开大型装配体非常卡,亲测可用解决方案

问题描述: 1.catia V5R21 32位 打开大型装配体非常卡 2.catia开启高速缓存后反而变卡 非常卡 卡死机 3.catia 在64位系统上安装32位的软件会不会影响性能发挥 4.明明电脑配置很高,比别人电脑配置高catia却比别人卡 5.catia跑不满CPU、内存、GPU&#xff…

STM32CubeIDE使用相关设置经验

1.修改字体大小 1)Window->Preferences->General->Appearance->Cofors and Fonts,然后在右侧C/C->Editor->C/C Editor Text Font,然后点击右侧的Edit…,修改对应的字体格式即可。 2)快捷方式&…

stm32 TIM定时器中断

一、TIM(Timer)定时器 定时器可以对输入的时钟进行计数,并在计数值达到设定值时触发中断; 16位计数器、预分频器、自动重装寄存器的时基单元,在72MHz计数时钟下可以实现最大59.65s的定时; 不仅具备基本的定…

STM32—ADC详解

文章目录 一.ADC简介二.ADC功能框图讲解1.电压输入范围2.输入通道3.转换顺序4.触发源5.转换时间6.数据寄存器7.中断8.电压转换 三.初始化结构体四.单通道电压采集1.头文件2.引脚配置函数3.NVIC配置函数4.ADC配置函数5.中断函数6.主函数 一.ADC简介 STM32f103系列有3个ADC&…

STM32CUBEMX配置教程(十一)STM32的ADC轮询模式扫描多个通道

STM32CUBEMX配置教程(十一)STM32的ADC轮询模式扫描多个通道 基于STM32H743VI 使用STM32CUBEMX两年了,始终觉得这个工具非常的方便,但因为不是经常使用,导致有些要点总是会有些遗忘,因此写下这一系列教程以…

stm32用tft-lcd 显示自定义大小的字体

笔者用的开发环境是正点原子的stm32 mini 版本,其中需要用到lcd显示中文,正点原子的例程上的字体显示得太小了,于是自己根据例程来写一个可以显示大点字体的函数。 1、首先打开取模软件pctolcd2002,选好字体并做相应设置,笔者想显…

广州大彩串口屏与STM32F407通讯

目录 广州大彩串口屏与STM32F407通讯一、大彩串口屏介绍二、硬件连接三、程序移植四、触摸屏组态及函数调用五、最终效果结语 广州大彩串口屏与STM32F407通讯 之前一直用正点原子的LCD屏,但是占用太多GPIO引脚,所以打算换一块串口屏,某宝上看…

STM32-GPIO介绍

目录 1.概述 2.GPIO工作原理 2.1 保护二极管及上下拉电阻 2.2 GPIO工作模式 2.2.1 浮空输入模式 2.2.2 上拉输入模式 2.2.3 下拉输入模式 2.2.4 模拟输入模式 2.2.5 开漏输出模式 2.2.6 开漏复用输出模式 2.2.7 推挽输出模式 2.2.8 推挽复用输出模式 2.3 注意事项 …