python與c互相調用


python與c互相調用

雖然python開發效率很高,但作為腳本語言,其性能不高,所以為了兼顧開發效率和性能,通常把性能要求高的模塊用c或c++來實現或者在c或c++中運行python腳本來處理邏輯,前者通常是python中一些模塊的實現方式,后者服務端程序(實現業務擴展或是Plugin功能)和游戲開發(腳本只處理邏輯)中比較常見。本文主要介紹通過在c中運行python腳本來實現python與c的相互調用,並通過c和python腳本設置同一段內存區域為例子來講解。

 

准備工作

  為了在c中運行python腳本,需要在程序鏈接的時候將python虛擬機庫鏈接進去,python虛擬機庫是python安裝目錄下libs中的python27.lib文件,至於怎樣將庫鏈接進程序中可以自己google下。由於在c中使用了python的一些方法和數據結構,所以需要將python安裝目錄下的include目錄添加到項目include目錄中。好了,需要准備的就是這些,然后就可以開始實現一個設置內存區域的例子了。

 

內嵌python虛擬機

  在c中內嵌python虛擬機很簡單,只需要在程序開頭include Python.h頭文件,然后調用下面兩段來初始化python虛擬機實例就行了。

1 Py_SetPythonHome("D:\Python27");
2 Py_Initialize();

  Py_SetPythonHome函數是用來設置python的庫路徑,也就是python安裝路徑,Py_Initialize函數真正實例化一個python虛擬機,這樣就把一個python虛擬機內嵌到c中了。

 

調用python腳本

   將python虛擬機初始化后,其實就可以調用python腳本了。c中調用腳本模塊中的方法分下面幾個步驟:

  1、使用PyImport_ImportModule導入腳步模塊;

  2、使用PyObject_GetAttrString獲取模塊特定方法信息;

  3、使用Py_VaBuildValue轉換輸入參數;

  4、使用PyObject_CallObject調用特定方法;

  5、使用PyArg_Parse轉換方法的返回結果。

  由於上面流程在調用模塊中的方法都是必須的,所以可以寫個函數來封裝上面的5個步驟,具體代碼如下:

  View Code

  有了上面的調用python模塊內方法的通用函數,我們就可以直接調用python腳本中的方法了,具體如下:

1 PyModuleRunFunction("hello", "test", "", 0, "()");

   這樣我們就實現了再c中調用python的方法。下面我們再來開心python怎么調用c中的方法。

 

初始化c實現的python模塊

   為了能在python腳本中調用到c中定義的方法,需要先在c中定義一個python模塊,然后在腳本中import這個模塊,最后通過這個模塊來間接調用c中定義的方法。例如,我們通過c定義了一塊內存區域data和對這個內存區域操作的函數SetData與GetData(代碼如下),怎樣在腳本中調用SetData與GetData函數來操作data呢?其實關鍵問題是怎么樣在腳本中調用SetData和GetData函數,如果能在腳本中調用這兩個函數,自然就能操作data了。python中通過模塊的方式來解決這個問題。

復制代碼
 1 #define min(a,b)    (((a) < (b)) ? (a) : (b))
 2 
 3 char data[1024];
 4 
 5 void SetData(const char *str)
 6 {
 7     strncpy(data, str, min(strlen(str) + 1, 1024));
 8 }
 9 
10 const char *GetData()
11 {
12     return data;
13 }
復制代碼

  在c中定義一個python模塊有特定的步驟,具體代碼如下:

  View Code

  Py_InitModule3用來定義一個python模塊,第一個參數是模塊的名字,第二個參數是模塊中的方法描述集合,第三個參數是模塊的描述信息。上面代碼中我們定義了一個叫pycallc的模塊,方法描述集合module_methods描述了兩個方法py_set_data和py_get_data,這兩個方法對應的函數地址是PySetData和PyGetData,這兩個函數最終會分別調用前面定義的SetData和GetData。這樣我們在python腳本中通過pycallc模塊的py_set_data和py_get_data方法就可以設置和獲取data數據了。看了上面的實現,其實這個python模塊的主要作用就是把c中定義的函數再封裝一次,封裝的函數能夠被python識別。

 

在python腳本中調用c實現的python模塊

   由於前面已經通過c代碼初始化了一個python模塊pycallc,那么在腳本中我們就可以通過import導入這個模塊,並調用這個模塊中的函數。具體代碼如下:

復制代碼
1 # -*- coding: utf-8 -*-
2 
3 import pycallc
4 
5 def test():
6     print 'in python : ', pycallc.py_get_data()
7     pycallc.py_set_data("change hello world!")
復制代碼

   這樣我們就實現了在python腳本中調用c中的方法。

  上面完整的代碼demo的鏈接:https://github.com/morningstatus/python/tree/master/ccallpy

 

總結

  從上面c調用python,python調用c,其實都是一些固定的步驟,知道就會用了,沒有會不會的問題,只有想不想知道的問題。沒有接觸這個技術前可能覺得它很高深,但其實只要稍微花點心思去了解它,它也其實沒有這么難。計算機很多技術不外乎都是這樣,只有你想不想的問題,沒有你會不會的問題,多問,多思考,多學習,總有一天你也能成為技術大牛。

 

參考

  python官方:https://docs.python.org/2/c-api/index.html


免責聲明!

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



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