IronPython初體驗


介紹

在 C# 程序中嵌入 IronPython 得到了很好的支持。在本教程中,我們將展示如何完成這個項目。
首先,我們將展示兩個非常基本的例子,說明如何執行一個不導入任何模塊的非常簡單的腳本。然后,再展示如何執行使用模塊的腳本。

在 C# 中執行 Python

第一個例子

我們來創建一個執行Python腳本的 C# 應用​​程序的簡單例子。我們使用 Visual Studio 2017 C# 控制台應用程序模板創建一個新項目。我們稱之為PythonScriptExecution1。完整的例子可以從我們的GitHub倉庫獲得:IronPythonTutorials / CSharpIntegration / PythonScriptExecution1
項目創建完成后,我們使用 NuGet 包管理器添加 IronPython 包,將其安裝到當前項目中。這會將以下程序集添加到項目中:

  • IronPython
  • IronPython.Model
  • IronPython.SQLite
  • IronPython.Wpf
  • Microsoft.Dynamic
  • Microsoft.Scripting
  • Microsoft.Scripting.AspNet
  • Microsoft.Scripting.Metadata

對於第一個例子,我們調用一個 Python 腳本,它將簡單地打印出 “Hello World!”。在控制台上。為了保持它盡可能簡單,我們只需將 Python 代碼硬編碼到一個字符串中,然后使用 CreateScriptSourceFromString 從中創建 Microsoft.Scripting.Hosting.ScriptSource 實例。正如你所看到的,這很容易做,只需要3行代碼。

static void Main(string[] args)
{
    var pythonEngin = IronPython.Hosting.Python.CreateEngine();
    var pythonScripts = pythonEngin.CreateScriptSourceFromString("print'hello world'");
    pythonScripts.Execute();
}

控制台輸出

hello world

如果你想了解更多關於在幕后發生的事情,你可以看看 IronPython Internals Foundations tutorial.

第二個例子

第二個例子與第一個例子幾乎相同,但是我們將使用 CreateScriptSourceFromFile 函數從文件中加載腳本,而不是將其硬編碼到一個字符串中。由於我們將腳本放在與 Program.cs 文件相同的目錄中,我們需要當從 Visual Studio 執行程序時,會出現兩個目錄。這就是為什么我們腳本的路徑是.. \ .. \ HelloWorld.py。您當然可以將腳本放在與可執行文件相同的目錄中。代碼如下所示。執行程序時,輸出當然與前面的示例相同。
完整的例子可以從我們的GitHub倉庫獲得:IronPythonTutorials/CSharpIntegration/PythonScriptExecution2

print('Hello World')
static void Main(string[] args)
{
    var pythonEngin = IronPython.Hosting.Python.CreateEngine();
    var pythonScripts = pythonEngin.CreateScriptSourceFromFile("..\\.\\HelloWorld.py"));
    pythonScripts.Execute();
    Console.ReadKey();
}

搜索路徑

通常,Python 腳本將依賴於某個模塊,或者是一個自定義模塊或 Python 標准庫中的模塊。我們將展示如何使用標准庫,但是考慮到大量的模塊,我們將從一個更基本的例子開始。
處理模塊的唯一困難是設置引擎將查找模塊的路徑列表。該ScriptEngine的類提供了一個函數來檢索的搜索路徑當前列表:GetSearchPaths,另一個設置列表:SetSearchPaths。SetSearchPaths 替換現有的列表,所以如果你想添加一個搜索路徑,你將需要首先獲取當前列表,添加新的路徑,然后將更新的列表傳遞給 SetSearchPaths 函數。
我們來舉例說明一個簡單的例子。我們修改之前的的一個示例,以便在 HelloWorld.py 導入另一個名為 HelloWorldModule.py 的模塊。我們把這兩個文件放在與Program.cs相同的目錄下。這兩個文件的來源如下所示。
完整的例子可以從我們的GitHub倉庫獲得:IronPythonTutorials/CSharpIntegration/PythonScriptExecution3

HelloWorldModule.py

def PrintHelloWorld():
    print("Hello World")

HelloWorld.py

import HelloWorldModule

HelloWorldModule.PrintHelloWorld()
static void Main(string[] args)
{
    var pythonEngin = IronPython.Hosting.Python.CreateEngine();
    Console.WriteLine("Search Paths:");
    var searchPaths = pythonEngin.GetSearchPaths();
    foreach (var item in searchPaths)
    {
        Console.WriteLine(item);
    }
    Console.WriteLine();
    searchPaths.Add("..\\..");
    pythonEngin.SetSearchPaths(searchPaths);

    var pythonScript = pythonEngin.CreateScriptSourceFromFile("..\\..\\HelloWorld.py");
    pythonScript.Execute();
}

顯然,這是一個稍微做作的例子,因為你通常會把腳本放在一個更合理的位置,但是你應該明白這個想法。
如果一切正常,你應該得到以下輸出。

Search Paths:
.
C:\Users\hippieZhou\Documents\Projects\IronPythonTutorials\03_PythonScriptExecution3\bin\Debug\Lib
C:\Users\hippieZhou\Documents\Projects\IronPythonTutorials\03_PythonScriptExecution3\bin\Debug\DLLs

Hello World

但是,如果由於某種原因無法找到一個模塊,你會得到下面的異常拋出。

Unhandled Exception: IronPython.Runtime.Exceptions.ImportException: No module na
med os
   at Microsoft.Scripting.Runtime.LightExceptions.CheckAndThrow(Object value)
   at Microsoft.Scripting.Interpreter.FuncCallInstruction`2.Run(InterpretedFrame
 frame)
   at Microsoft.Scripting.Interpreter.Interpreter.Run(InterpretedFrame frame)
   at Microsoft.Scripting.Interpreter.LightLambda.Run1[T0,TRet](T0 arg0)
   at IronPython.Compiler.RuntimeScriptCode.InvokeTarget(Scope scope)
   at IronPython.Compiler.RuntimeScriptCode.Run()
   at Microsoft.Scripting.Hosting.ScriptSource.Execute()
   at PythonScriptExecution3.Program.Main(String[] args) in c:\p4client2\Tutoria
ls\Development\IronPython\Examples\CSharpIntegration\PythonScriptExecution3\Pyth
onScriptExecution3\Program.cs:line 16

讓我們仔細看一下搜索路徑的初始列表。
默認情況下,當前工作目錄將包含在搜索路徑列表中。但是,如果您依賴於此,您的應用程序將會工作與否,具體取決於用戶啟動應用程序時當前的工作目錄。在默認情況下,IronPython 將在搜索路徑中包含兩條與應用程序本身安裝位置相關的路徑:在上面的輸出中可以看到的Lib和DLL路徑。這些位置是將模塊與主應用程序保持在一起的好選擇。

IronPython 實現使用 Assembly.GetEntryAssembly() 函數來獲取主機的路徑,以便添加 “Lib” 和 “DLL” 路徑。有些情況下,Assembly.GetEntryAssembly()將返回 null,這些路徑將不會被添加。一個這樣的情況是,當環境是 ASP.NET。

標准庫

在您的應用程序中使用標准庫並不困難。包含標准庫的單獨的NuGet包可用。這個包將所有的標准庫模塊添加到 Visual Studio 項目中。出現的問題是,應用程序使用的模塊需要與它分發。如何做到這一點取決於具體情況。在最簡單的情況下,您可以將所需的模塊放在與應用程序二進制文件相同的目錄中,並將它們一起分發。如果您選擇該解決方案,則默認搜索路徑應該足夠,因為它包含“。” 目錄。
現在讓我們來看一個使用標准庫的腳本的簡單例子。完整的例子可以從我們的 GitHub 倉庫獲得:IronPythonTutorials/CSharpIntegration/PythonScriptExecution4

使用 NuGet 獲取 IronPython 標准庫:IronPython.StdLib
HelloWorldBase64.py

import base64

originalString = b"Hello World!"
print("OriginalString:" + str(originalString))

encodedString = base64.b64encode(originalString)
print("EncodedString:" + str(encodedString))

decodedString = base64.b64decode(encodedString);
print("Decoded String:" + str(decodedString))

C#

static void Main(string[] args)
{
    var pythonEngin = IronPython.Hosting.Python.CreateEngine();
    Console.WriteLine("Search paths:");
    var searchPaths = pythonEngin.GetSearchPaths();
    foreach (var path in searchPaths)
    {
        Console.WriteLine(path);
    }
    Console.WriteLine();

    searchPaths.Add("..\\..\\Lib");
    pythonEngin.SetSearchPaths(searchPaths);

    var pythonScript = pythonEngin.CreateScriptSourceFromFile("..\\..\\HelloWorldBase64.py");
    pythonScript.Execute();
}

輸出

Search paths:
.
C:\Users\hippieZhou\Documents\Projects\IronPythonTutorials\04_PythonScriptExecution4\bin\Debug\Lib
C:\Users\hippieZhou\Documents\Projects\IronPythonTutorials\04_PythonScriptExecution4\bin\Debug\DLLs

OriginalString:Hello World!
EncodedString:SGVsbG8gV29ybGQh
Decoded String:Hello World!

共享變量

在 Microsoft.Scripting.Hosting.ScriptScope 類用於保存的是當前在范圍內的變量及其關聯值列表。本 ScriptScope 類提供的方法來設置,獲取和范圍刪除變量。他們是 SetVariable, GetVariable 和 RemoveVariable。要獲取范圍中所有變量的列表,請使用GetVariableNames 方法。
在我們最開始的例子中,我們使用 pythonScript.Execute(); 來運行腳本。無參數 Execute() 函數在 ScriptScope 內部創建實例,因此調用者無法訪問它。但是,我們可以使用其他重載來創建 ScriptScope 自己並將其傳遞給 Execute() 函數。
以下示例顯示了如何使用這些函數。完整的例子可以從我們的GitHub倉庫獲得:IronPythonTutorials/CSharpIntegration/PythonScriptExecution5

Program.cs

static void Main(string[] args)
{
    var pythonEngin = IronPython.Hosting.Python.CreateEngine();
    var pythonScript = pythonEngin.CreateScriptSourceFromString(
        "helloWorldString='Hello World!'\n" + 
        "print(helloWorldString) \n" + 
        "print(extrnalString)");

    var scope = pythonEngin.CreateScope();
    scope.SetVariable("extrnalString", "How are you.");
    pythonScript.Execute(scope);
    Console.WriteLine();
    Console.WriteLine("List of variables in the scope:");
    foreach (var name in scope.GetVariableNames())
    {
        Console.Write(name+ "   ");
    }
    Console.WriteLine();
    Console.WriteLine("Variable values:");
    Console.WriteLine("helloWorldString:" + scope.GetVariable("helloWorldString"));
    Console.WriteLine("extrnalString:" + scope.GetVariable("extrnalString"));

    Console.ReadKey();
}

輸出

Hello World!
How are you.

List of variables in the scope:
extrnalString   __builtins__   __file__   __name__   __doc__   helloWorldString
Variable values:
helloWorldString:Hello World!
extrnalString:How are you.

在這個例子中,腳本定義了這個 helloWorldString 變量,並使用了一個 externalString 在腳本中沒有定義的變量 。然后打印這兩個變量。
該 externalString 變量顯示了C# 代碼如何使用該 SetVariable 方法將變量添加到腳本可以使用的范圍。
腳本執行后,范圍包含由腳本添加的變量列表。C# 代碼使用我們前面提到的各種函數來打印執行后的范圍內的內容。

導入模塊

在本教程前面,我們看到了 Python 腳本如何使用 Python import 語句,只要搜索路徑設置正確,就可以像任何常規的 Python 腳本一樣使用Python 語句。在這里我們提出另一個有趣的方法,即從 C# 代碼中導入模塊,而不是 Python 代碼。
靜態 IronPython.Hosting.Python.ImportModule 函數可以用來導入一個模塊。它返回 ScriptScope 包含導入模塊中所有變量的類的一個實例。該 ScriptScope 在上面有解釋。例如,您可以使用返回的作用域並將其傳遞給 ScriptSource.Execute 函數,以執行另一個可以使用導入模塊的功能的 Python 腳本,甚至可以使用它直接從 C# 執行 Python 方法,如下面的示例所示。
將 ImportModule 搜索路徑中的模塊作為 Python import 語句進行查找將會這樣做,重要的是正確設置路徑或找不到模塊。
以下示例顯示了如何在 Python 模塊中定義的函數可以像 C# 函數一樣執行。

HelloWorldModule.py

def PrintHelloWorld():
    print("Hello World!")

def PrintMessage(message):
    print(message)

def Add(arg1,arg2):
    return (arg1 + arg2)

Program.cs

static void Main(string[] args)
{
    var pythonEngin = IronPython.Hosting.Python.CreateEngine();
    var searchPaths = pythonEngin.GetSearchPaths();
    searchPaths.Add("..\\..");
    pythonEngin.SetSearchPaths(searchPaths);

    var scope = IronPython.Hosting.Python.ImportModule(pythonEngin, "HelloWorldModule");

    dynamic printHelloWorldFunction = scope.GetVariable("PrintHelloWorld");
    printHelloWorldFunction();

    dynamic printMessageFunction = scope.GetVariable("PrintMessage");
    printMessageFunction("GoodBye!");

    dynamic addFunction = scope.GetVariable("Add");
    Console.WriteLine("The sum of 1 and 2 is " + addFunction(1,2));

    Console.ReadKey();
        }

總結

官網給的示例教程是 Visual Studio 2013 + python 2.x 版本的,對於 Visual Studio 2017 + Python 3.X 版本的使用方式影響不大。按照官網描述一步一步還是可以完成整個的基本教程。
個人理解:IronPython 其實就是相當於將 Python 編譯成字節碼,然后通過 IronPython 創建的虛擬 Python 運行環境(類似虛擬機)從而達到能夠運行 Python 的目的。經過個人(不科學的)測試,這種模式的運行效率並不是很高,在 Python 慢的基礎上還要慢一個節拍。所以,想在生產環境中使用的話需要慎重考慮。

參考

  1. IronPython C# Integration


免責聲明!

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



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