[Python] Python 調用 C 共享庫


  Linux/Unix 平台下共享庫(Shared Library)文件后綴 .so;在 Windows 平台稱為動態鏈接庫(Dynamic Link Library),文件名后綴為 .dll。


 

 

利用 ctypes 模塊調用 C 共享庫

 

  ctypes 是 Python 標准庫提供的一個模塊,Python 2.3 版本以上支持該模塊。ctypes 是 Python 高級外部函數接口,Python 通過它可以調用 C 語言編譯的靜態鏈接庫和動態鏈接庫。ctypes 支持多個平台,包括 Windows, Windows CE, Mac OS X, Linux, Solaris, FreeBSD, OpenBSD。

 

  ctypes 模塊定義了一些基礎 C 兼容數據類型,具體類型請點擊此處查看。

 

  以下實例演示如何在 Python 程序中使用 ctypes 模塊來調用 C 程序函數。

 

1. 准備 C 程序源文件 sum.c

 

  在 sum.c 源文件定義一個 sum() 函數,用以計算 N 個連續自然數之和。

#include <stdio.h>

int main(void){
    int x;
    printf("Input an integer:\n");
    scanf("%d", &x);
    printf("sum=%d\n", sum(x));
    return 0;
};

int sum(int x){
    int i, result=0;
    for(i=0; i<=x; i++){
        result+=i;
    }
    return result;
};

 

2. 將 C 源代碼編譯成共享庫文件 sum.so

 

  使用 gcc 編譯器將 sum.c 編譯為共享庫文件 sum.so。

$ gcc sum.c -fPIC -shared -o sum.so

 

3. 准備 Python 模塊 sum.py

 

  在 sum.py 模塊中我們定義一個 py_sum() 函數,該函數是 sum.c 文件中 sum() 函數的 Python 實現。

#!/usr/bin/env python
# -*- coding: utf8 -*-

import ctypes

so = ctypes.CDLL('./sum.so')

def display_dict():
    print "Type of so is %s" % type(so)
    print "Attributes before calling so.sum: %s" % dir(so)
    print "so.sum(10) = %s" % so.sum(10)
    print "Attributes after calling so.sum: %s" % dir(so)


def py_sum(x):
    y = 0
    for i in range(x+1):
        y += i
    return y


def so_sum(x):
    return so.sum(x)


if __name__ == "__main__":
    pass

 

  在 Python 模塊中 import ctypes,然后通過 ctypes.CDLL() 方法導入共享庫文件 sum.so,之后就可以直接調用動態庫提供的函數。

  

4. 測試 Python 調用共享庫

 

  讓我們在 __main__ 區塊中調用 display_dict 函數:

if __name__ == "__main__":
    display_dict()

 

  運行 sum.py 查看結果:

$ python sum.py
Type of so is <class 'ctypes.CDLL'>
Attributes before calling so.sum: ['_FuncPtr', '__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattr__', '__getattribute__', '__getitem__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_func_flags_', '_func_restype_', '_handle', '_name']
so.sum(10) = 55
Attributes after calling so.sum: ['_FuncPtr', '__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattr__', '__getattribute__', '__getitem__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_func_flags_', '_func_restype_', '_handle', '_name', 'sum']

 

  從結果可以發現 .so 共享庫導入到 .py 模塊中得到一個 ctypes.CDLL 對象。調用了 C 函數之后,CDLL 對象會將該函數添加到對象屬性中。(在調用 sum 函數之后,CDLL 對象屬性列表中才包含了 sum 函數。)

 

5. Python 調用共享庫的性能

 

  我們修改一下 sum.py 模塊:

if __name__ == "__main__":
    import timeit
    i = 10000
    print "py_sum(%s) = %s" % (i, py_sum(i))
    print "so_sum(%s) = %s" % (i, so_sum(i))

    print timeit.timeit("py_sum(10000)", setup="from __main__ import py_sum", number=1000)
    print timeit.timeit("so_sum(10000)", setup="from __main__ import so_sum", number=1000)

 

  查看運行結果:

$ python sum.py
py_sum(10000) = 50005000
so_sum(10000) = 50005000
6.82061600685
0.158802986145

 

  以上測試顯示,循環疊加 10000 次,執行代碼 1000 次,Python 代碼耗費了 6.820 秒,C 代碼耗費了 0.158 秒,Python 代碼耗費時間是 C 代碼耗費時間的 42.95 倍。

 


免責聲明!

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



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