實用技能之Python調用C 或者C#開發的DLL動態庫

2024年2月6日 19点热度 0人点赞

前言

Python作為一門高級編程語言,可以快速地實現各種復雜的業務邏輯和算法。但對於一些計算密集型任務,Python的執行效率可能不盡如人意。此時,我們可以考慮使用C/C 等底層語言來編寫性能更高的代碼,並通過動態鏈接庫(DLL)的方式,在Python中調用這些代碼。

在實際開發中,Python調用DLL的場景非常廣泛。例如,使用第三方庫、訪問硬件接口、提高性能、調用系統函數和與其他語言交互等。通過DLL,Python可以方便地調用各種底層接口,從而使得Python可以勝任更多的任務。同時,Python也可以通過自己編寫DLL,為其他編程語言提供API。

無論你是在使用第三方庫、訪問硬件、提高性能還是與其他語言交互,使用Python調用DLL都是一個非常有用的技能。

應用場景

Python調用DLL的場景有很多,下面列舉了一些常見的應用場景

  1. 使用第三方庫:某些功能可能由C或C 編寫的第三方庫提供。通過加載該庫的DLL,可以在Python中使用這些功能。例如,NumPy和SciPy庫中的一些數學和科學計算函數就是使用C/C 實現的。
  2. 訪問硬件接口:許多硬件設備(如傳感器、機器人等)提供了C/C 的接口庫。通過調用相應的DLL,可以與這些硬件進行交互。例如,通過加載USB驅動程序的DLL,可以在Python中讀取和控制USB設備。
  3. 提高性能:對於某些計算密集型任務,用C/C 編寫的代碼通常比Python代碼運行得更快。通過將這些代碼封裝為DLL,並在Python中調用,可以在性能要求較高的場景下提高程序執行速度。
  4. 調用系統函數:一些操作系統提供了C/C 編寫的底層接口函數,通過調用相應的DLL,可以在Python中訪問和操作這些接口。例如,Windows API中的許多函數可以通過加載相應的DLL來在Python中調用。
  5. 與其他語言交互:如果你在項目中使用了多種編程語言,可以使用DLL作為它們之間的橋梁。通過在一個語言中編寫DLL,然後在另一個語言中加載和調用它,可以實現不同語言之間的數據交換和函數調用。

在使用ctypes加載和調用DLL時,需要確保DLL文件已經正確編譯,並且函數和數據類型與Python進行正確的交互。同時,還需要註意在不同平臺上可能存在的差異,如文件擴展名、路徑分隔符等。

Python調用DLL動態庫

本次實驗使用的Python版本為 3.10.2 64位

Python加載C 編寫的DLL

在Python中加載C 編寫的DLL(動態鏈接庫)可以使用ctypes庫。以下是一個示例代碼,展示了如何加載C 編寫的DLL並調用其中的函數:

// mydll.cpp
#include <iostream>
extern "C" __declspec(dllexport) int Add(int a, int b)
{
    return a   b;
}
import ctypes
# 加載DLL
mydll = ctypes.CDLL("./mydll.dll")
# 獲取函數指針
add_func = mydll.Add
add_func.restype = ctypes.c_int   # 指定返回值類型
add_func.argtypes = [ctypes.c_int, ctypes.c_int]   # 指定參數類型
# 調用函數
result = add_func(1, 2)
print("Sum is:", result)

首先編寫mydll.dll的DLL文件,位於當前工作目錄下。你需要將路徑修改為實際的DLL文件路徑。

在這個示例中,我們首先使用ctypes.CDLL函數加載了DLL文件,並將其命名為mydll。然後,通過mydll.add獲取了DLL中的Add函數,並使用restype屬性指定了返回值類型,使用argtypes屬性指定了參數類型。最後,我們可以直接調用add_func來執行函數。

需要根據實際情況修改和擴展上述代碼,特別是在指定返回值類型和參數類型時要保持與DLL中函數定義的一致性。另外,如果DLL中包含類的定義,還可以使用ctypes來獲取類的實例並調用其成員函數。

Python加載C#編寫的DLL

在Python中使用Pythonnet庫來實例化.NET開發的DLL中的類,並調用其中的非靜態方法.下面是一個示例代碼。現在,我們可以使用Pythonnet來在Python中調用這個DLL。

首先,需要安裝 pythonnet 3.0.3庫:

pip install pythonnet

編寫C#代碼,C#構建動態庫有三種形式,Net4.0、Net4之後的版本、Net Standard等。

namespace Net4Library
{
	public class Person
    {
        private string name;
        public Person(string name)
        {
            this.name = name;
        }
        public void Greet()
        {
            Console.WriteLine($"Hello, {name}!");
        }
    }
}
namespace Net6Library
{
	//同上
}
namespace NetStandardLibrary
{
	//同上
}
import clr
clr.AddReference("Net4Library")  # 加載DLL
from Net4Library import Person
person = Person("Alice")   # 實例化類
person.Greet()             # 調用非靜態方法

我們首先使用clr.AddReference函數加載了Net4Library。然後,通過from Net4Library import Person導入了Person類。接下來,我們使用Person類的構造函數,傳遞一個名稱參數來實例化一個Person對象。最後,我們調用person.Greet()方法來輸出問候語。

參考文檔

#程序員生活指南# #記錄我的2024# #頭條創作挑戰賽# #萬能生活指南# #自律學習計劃#

#編程經驗#