在.Net Framework中調用Python的腳本方法 (以VB和C#為例)


某個項目中涉及到這樣一個情景: VB/C#寫的原始項目要調用Python的一些方法完成特殊的操作, 那么這就涉及到了,在.Net Framework中如何調用Python的腳本方法。

具體步驟流程如下所示:

1): 展示一個簡單的Python代碼,即傳遞一個參數,然后返回修改后字符串,此文件名稱為 mytest.py

def MyTestFunction(name):
    return "testing " + name

2): 我們借助第三方的工具來實現這個操作,那么這個第三方工具就是 IronPython,IronPython是一種在.Net及Mono上的Python實現,是一個基於微軟的DLR引擎的開源項目,可以去這里下載或者跟蹤源代碼(https://github.com/IronLanguages/ironpython2)。 然后我們可以到這個鏈接中下載安裝文件(https://github.com/IronLanguages/ironpython2/releases/tag/ipy-2.7.8), 安裝文件安裝完之后我們可以到對應的安裝目錄下面找到我們所需要的dll(IronPython.dll, IronPython.Modules.dll, Microsoft.Dynamic.dll, Microsoft.Scripting.dll)以及一個名為Lib的文件夾,如下圖所示:

3):我們用VS創建一個VB的工程,然后將上面的這四個dll引用進來,之后就可以進行具體的調用了,假設我們的Python代碼文件放置的目錄是 D:\Code\PyTest\mytest.py 必要時請將此文件copy到VB執行目錄中, 然后把對應的pythonPath換掉

如下代碼所示:

Imports IronPython.Hosting
Imports Microsoft.Scripting.Hosting

Public Class Form1
    Private Sub CallPython()
        Dim pythonPath = "D:\Code\PyTest\mytest.py"
        Dim pyruntime as ScriptRuntime = Python.CreateRuntime()
        Dim fileObj As Object = pyruntime.UseFile(pythonPath)
        Dim result = fileObj.MyTestFunction("World")
    End Sub
End Class

這樣我們就通過IronPython完成了VB調用Python腳本方法,我們可以繼續參考如下連接: https://blog.csdn.net/letunihao/article/details/41985163

 

這里Python的腳本方法非常單純無暇,沒有任何的其他腳本的引用, 但是實際項目中這樣單純的代碼大多是沒有意義的,總會引用其他的module來實現更加復雜的邏輯。

下面我們就要進階了,如果Python腳本之間有相互的引用,如何完成我們的目標呢?請看如下步驟

4):在相同的目錄中創建另外一個Python文件來實現文件的讀寫,文件名為 mytest_common.py,

import os

class FileOperator:
    
    def WriteInfoToFile(self, path):
        file = open(path, "w")
        file.write("Hello World")
        file.close()

    def ReadInfoFromFile(self, path):
        fileInfo = ""
        data = open(path)
        for each_line in data:
            fileInfo += each_line
        data.close()
        return fileInfo

為什么實現方法的時候要加入一個額外的參數 self?

請看如下連接: https://stackoverflow.com/questions/23944657/typeerror-method-takes-1-positional-argument-but-2-were-given/42016399

文件讀寫請參考 (http://www.pythonforbeginners.com/files/reading-and-writing-files-in-python)

 

5):然后我們對 mytest.py 文件做如下修改,假設我們已經通過Python自己運行WriteInfoToFile方法已經生成了一個Test.txt文件

from mytest_common import FileOperator

def MyTestReadInfo():
    fInfo = fOperator.ReadInfoFromFile("D:\Code\PyTest\Test.txt")
    return fInfo

fOperator = FileOperator()

6):然后我們用如下VB代碼進行對新的Python腳本方法的調用

Imports IronPython.Hosting
Imports Microsoft.Scripting.Hosting

Public Class Form1
    Private Sub CallPython()
        Dim pythonPath = "D:\Code\PyTest\mytest.py"
        Dim pyruntime as ScriptRuntime = Python.CreateRuntime()
        Dim fileObj As Object = pyruntime.UseFile(pythonPath)
        Dim result = fileObj.MyTestReadInfo()
    End Sub
End Class

會throw exception說:某某某某module無法加載, 或者是找不到某某module。Unhandled Exception: IronPython.Runtime.Exceptions.ImportException: No module named ... 原因是:Python自己運行的時候會自動加載對應相關聯的module,特別是一些系統的module,比如這里面的 os, 但是我們通過外部調用的時候無法自動建立這樣的鏈接,因為我們要在Python的源文件中明確指明所引用的那些系統源文件所在folder,讓其可以在指定的folder下面去尋找相關聯的源文件。

那么這些源文件在什么地方呢?我們可以到Python的安裝目錄下尋找,也可以到我們第2步 IronPython的安裝目錄下面尋找,即Lib文件夾,然后將此文件夾copy到我們的測試Python的同級文件夾,用相對路徑指定,當然你也可以不用copy,然后用絕對路徑定位到Lib文件夾即可

代碼如下所示:

import sys
sys.path.append(".\Lib")

from mytest_common import FileOperator

def MyTestReadInfo():
    fInfo = fOperator.ReadInfoFromFile("D:\Code\PyTest\Test.txt")
    return fInfo

fOperator = FileOperator()

這樣我們再用第6步中的VB代碼去調用就可以成功了。

注:使用相對路徑時,請注意使用文件的位置,保證能夠成功定位到。

更多詳細信息可以參考如下連接:

https://stackoverflow.com/questions/6195781/ironpython-exe-compiled-using-pyc-py-cannot-import-module-os

https://thesesergio.wordpress.com/2013/09/11/how-to-generate-and-use-a-exe-that-uses-net-dlls-with-ironpython-pyc-py/

https://blog.csdn.net/letunihao/article/details/41985163

 

 

給出C#部分代碼以作參考

        public static dynamic GetPythonFileObj()
        {
            var fath = AppContext.BaseDirectory + @"Services\PythonService.py";

            var pyruntime = Python.CreateRuntime();
            var pyengine = pyruntime.GetEngine("Python");
            var paths = pyengine.GetSearchPaths();
            paths.Add(AppContext.BaseDirectory + @"Services");
            paths.Add(AppContext.BaseDirectory + @"Services\Lib");
            pyengine.SetSearchPaths(paths);

            dynamic fileObj = pyruntime.UseFile(fath);
            return fileObj;
        }


        public static string UploadTag(ref dynamic fileObj, string tagName)
        {
            var tagValue = fileObj.ex_read(tagName);
            return tagValue.ToString();
        }
View Code

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM