1. 程式人生 > >c#呼叫python的四種方法(嘗試了四種,只詳細講解本人成功的後兩種,其餘方法只列出,詳細用法請自行谷歌百度)

c#呼叫python的四種方法(嘗試了四種,只詳細講解本人成功的後兩種,其餘方法只列出,詳細用法請自行谷歌百度)

一、使用c#,nuget管理包上下載的ironPython安裝包

     嘗試後發現,對引用了numpy等第三方庫的python程式碼,會報找不到模組xxx的錯誤,上網查證後發現此問題基本難以解決


二、使用c++程式呼叫python檔案,然後將其做成動態連結庫(dll),在c#中呼叫此dll檔案
     限制:實現方式很複雜,並且受python版本、(python/vs)32/64位影響,而且要求使用者必須安裝python執行環境

三、使用安裝好的python環境,利用c#命令列,呼叫.py檔案執行

      優點:執行速度只比在python本身環境中慢一點,步驟也相對簡單

      缺點:需要使用者安裝配置python環境

      實用步驟:

      1、下載安裝python,並配置好環境變數等(本人用的Anaconda,連結此處不再提供)

       2、編寫python檔案(這裡為了便於理解,只傳比較簡單的兩個引數)  

注:這兩個python檔案,我引用了numpy第三方庫,也要安裝後才能在python中使用

#multi.py

def multiplication(a,b):
	return a*b
#main.py
import numpy as np
import multi
import sys

def func(a,b):
    result=np.sqrt(multi.multiplication(int(a),int(b)))
    return result


if __name__ == '__main__':
    print(func(sys.argv[1],sys.argv[2]))

ps:為了import不報錯,儘量把multi.py檔案放main.py同一資料夾下。因為打包exe檔案執行後,可能會報找不到Multi模組的錯誤  

      3、在c#中呼叫上述主python檔案:main.py

      (我直接建了一個wpf檔案,放在一個按鈕的點選事件中執行了,你們隨意)

        private void Button_Click(object sender, RoutedEventArgs e)
        {

            string[] strArr=new string[2];//引數列表
            string sArguments = @"main.py";//這裡是python的檔名字
            strArr[0] = "2";
            strArr[1] = "3";
            RunPythonScript(sArguments, "-u", strArr);
        }
        //呼叫python核心程式碼
        public static void RunPythonScript(string sArgName, string args = "", params string[] teps)
        {
            Process p = new Process();
            string path = System.AppDomain.CurrentDomain.SetupInformation.ApplicationBase + sArgName;// 獲得python檔案的絕對路徑(將檔案放在c#的debug資料夾中可以這樣操作)
            path = @"C:\Users\user\Desktop\test\"+sArgName;//(因為我沒放debug下,所以直接寫的絕對路徑,替換掉上面的路徑了)
            p.StartInfo.FileName = @"D:\Python\envs\python3\python.exe";//沒有配環境變數的話,可以像我這樣寫python.exe的絕對路徑。如果配了,直接寫"python.exe"即可
            string sArguments = path;
            foreach (string sigstr in teps)
            {
                sArguments += " " + sigstr;//傳遞引數
            }

                sArguments += " " + args;

            p.StartInfo.Arguments = sArguments;

            p.StartInfo.UseShellExecute = false;

            p.StartInfo.RedirectStandardOutput = true;

            p.StartInfo.RedirectStandardInput = true;

            p.StartInfo.RedirectStandardError = true;

            p.StartInfo.CreateNoWindow = true;

            p.Start();
            p.BeginOutputReadLine();
            p.OutputDataReceived += new DataReceivedEventHandler(p_OutputDataReceived);
            Console.ReadLine();
            p.WaitForExit();
        }
        //輸出列印的資訊
        static void p_OutputDataReceived(object sender, DataReceivedEventArgs e)
        {
            if (!string.IsNullOrEmpty(e.Data))
            {
                AppendText(e.Data + Environment.NewLine);
            }
        }
        public delegate void AppendTextCallback(string text);
        public static void AppendText(string text)
        {
            Console.WriteLine(text);     //此處在控制檯輸出.py檔案print的結果

        }

執行成功,得到結果:也就是\sqrt{2*3}


四、c#呼叫python可執行exe檔案,使用命令列進行傳參取返回值

      優點:無需安裝python執行環境

      缺點:

       1、可能是因為要展開exe中包含的python環境,執行速度相當慢,慎用!

       2、因為是命令列傳參形式,故傳參需要自行處理。ps:由於命令列傳參形式為:xxx.exe 引數1 引數2 引數3....

我要傳一個很大的陣列,曲線救國,用c#將陣列寫入txt檔案中,將存放路徑傳給python函式,python讀取此txt檔案得到資料


     使用步驟:

      1、編寫python檔案(這裡為了便於理解,只傳比較簡單的兩個引數)  

#multi.py

def multiplication(a,b):
	return a*b
#main.py
import numpy as np
import multi
import sys

def func(a,b):
    result=np.sqrt(multi.multiplication(int(a),int(b)))
    return result


if __name__ == '__main__':
    print(func(sys.argv[1],sys.argv[2]))

ps:為了import不報錯,儘量把multi.py檔案放main.py同一資料夾下。因為打包exe檔案執行後,可能會報找不到Multi模組的錯誤

2、安裝pyInstaller(若已安裝請直接跳過此步驟)

      我使用的是Anaconda編寫python,所以使用Anaconda Prompt進行安裝pyInstaller(直接安裝python並配好環境變數的小夥伴,可以在電腦的cmd下進行操作)

      

這個類似於電腦的cmd.exe程式,可在其中輸入命令列操作

安裝pyInstaller命令列:

正常來講會報一個錯誤,說你的pip版本過低,需要先更新一下

pip install --upgrade pip

使用此命令更新pip,然後再執行pip install pyinstaller命令即可

3、使用pyinstaller打包python程式

同樣還是在Anaconda Prompt中,cd python檔案所在的路徑,然後執行打包命令

打包過程可能會出錯(找不到模組、迭代深度超出等,在我另兩篇部落格裡有解決辦法)

若打包成功,出現successfully,失敗的話會給出錯誤資訊

4、在c#中呼叫此exe檔案(此處我建了一個wpf專案,利用按鈕點選事件來實現呼叫)

namespace WpfTest2
{
    /// <summary>
    /// MainWindow.xaml 的互動邏輯
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            //string debugPath = System.Environment.CurrentDirectory;           //此c#專案的debug資料夾路徑
            string pyexePath = @"C:\Users\user\Desktop\test\dist\main.exe";     
            //python檔案所在路徑,一般不使用絕對路徑,此處僅作為例子,建議轉移到debug資料夾下
            
            Process p = new Process();
            p.StartInfo.FileName = pyexePath;//需要執行的檔案路徑
            p.StartInfo.UseShellExecute = false; //必需
            p.StartInfo.RedirectStandardOutput = true;//輸出引數設定
            p.StartInfo.RedirectStandardInput = true;//傳入引數設定
            p.StartInfo.CreateNoWindow = true;
            p.StartInfo.Arguments = "2 3";//引數以空格分隔,如果某個引數為空,可以傳入””
            p.Start();
            string output = p.StandardOutput.ReadToEnd();
            p.WaitForExit();//關鍵,等待外部程式退出後才能往下執行}
            Console.Write(output);//輸出
            p.Close();        
        }
    }
}

在控制檯打印出結果:也就是\sqrt{2*3}

至此,完成c#呼叫python的exe檔案,並實現了傳入傳出引數功能,謝謝觀看