pythonc交互
1. 怎樣讓python腳本與C++程序互相調用
二、Python調用C/C++
1、Python調用C動態鏈接庫
Python調用C庫比較簡單,不經過任何封裝打包成so,再使用python的ctypes調用即可。
(1)C語言文件:pycall.c
[html] view plain
/***gcc -o libpycall.so -shared -fPIC pycall.c*/
#include <stdio.h>
#include <stdlib.h>
int foo(int a, int b)
{
printf("you input %d and %d\n", a, b);
return a+b;
}
(2)gcc編譯生成動態庫libpycall.so:gcc -o libpycall.so -shared -fPIC pycall.c。使用g++編譯生成C動態庫的代碼中的函數或者方法時,需要使用extern "C"來進行編譯。
(3)Python調用動態庫的文件:pycall.py
[html] view plain
import ctypes
ll = ctypes.cdll.LoadLibrary
lib = ll("./libpycall.so")
lib.foo(1, 3)
print '***finish***'
(4)運行結果:
2、Python調用C++(類)動態鏈接庫
需要extern "C"來輔助,也就是說還是只能調用C函數,不能直接調用方法,但是能解析C++方法。不是用extern "C",構建後的動態鏈接庫沒有這些函數的符號表。
(1)C++類文件:pycallclass.cpp
[html] view plain
#include <iostream>
using namespace std;
class TestLib
{
public:
void display();
void display(int a);
};
void TestLib::display() {
cout<<"First display"<<endl;
}
void TestLib::display(int a) {
cout<<"Second display:"<<a<<endl;
}
extern "C" {
TestLib obj;
void display() {
obj.display();
}
void display_int() {
obj.display(2);
}
}
(2)g++編譯生成動態庫libpycall.so:g++ -o libpycallclass.so -shared -fPIC pycallclass.cpp。
(3)Python調用動態庫的文件:pycallclass.py
[html] view plain
import ctypes
so = ctypes.cdll.LoadLibrary
lib = so("./libpycallclass.so")
print 'display()'
lib.display()
print 'display(100)'
lib.display_int(100)
(4)運行結果:
3、Python調用C/C++可執行程序
(1)C/C++程序:main.cpp
[html] view plain
#include <iostream>
using namespace std;
int test()
{
int a = 10, b = 5;
return a+b;
}
int main()
{
cout<<"---begin---"<<endl;
int num = test();
cout<<"num="<<num<<endl;
cout<<"---end---"<<endl;
}
(2)編譯成二進制可執行文件:g++ -o testmain main.cpp。
(3)Python調用程序:main.py
[html] view plain
import commands
import os
main = "./testmain"
if os.path.exists(main):
rc, out = commands.getstatusoutput(main)
print 'rc = %d, \nout = %s' % (rc, out)
print '*'*10
f = os.popen(main)
data = f.readlines()
f.close()
print data
print '*'*10
os.system(main)
(4)運行結果:
4、擴展Python(C++為Python編寫擴展模塊)
所有能被整合或導入到其它python腳本的代碼,都可以被稱為擴展。可以用Python來寫擴展,也可以用C和C++之類的編譯型的語言來寫擴展。Python在設計之初就考慮到要讓模塊的導入機制足夠抽象。抽象到讓使用模塊的代碼無法了解到模塊的具體實現細節。Python的可擴展性具有的優點:方便為語言增加新功能、具有可定製性、代碼可以實現復用等。
為 Python 創建擴展需要三個主要的步驟:創建應用程序代碼、利用樣板來包裝代碼和編譯與測試。
(1)創建應用程序代碼
[html] view plain
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int fac(int n)
{
if (n < 2) return(1); /* 0! == 1! == 1 */
return (n)*fac(n-1); /* n! == n*(n-1)! */
}
char *reverse(char *s)
{
register char t, /* tmp */
*p = s, /* fwd */
*q = (s + (strlen(s) - 1)); /* bwd */
while (p < q) /* if p < q */
{
t = *p; /* swap & move ptrs */
*p++ = *q;
*q-- = t;
}
return(s);
}
int main()
{
char s[BUFSIZ];
printf("4! == %d\n", fac(4));
printf("8! == %d\n", fac(8));
printf("12! == %d\n", fac(12));
strcpy(s, "abcdef");
printf("reversing 'abcdef', we get '%s'\n", \
reverse(s));
strcpy(s, "madam");
printf("reversing 'madam', we get '%s'\n", \
reverse(s));
return 0;
}
上述代碼中有兩個函數,一個是遞歸求階乘的函數fac();另一個reverse()函數實現了一個簡單的字元串反轉演算法,其主要目的是修改傳入的字元串,使其內容完全反轉,但不需要申請內存後反著復制的方法。
(2)用樣板來包裝代碼
介面的代碼被稱為「樣板」代碼,它是應用程序代碼與Python解釋器之間進行交互所必不可少的一部分。樣板主要分為4步:a、包含Python的頭文件;b、為每個模塊的每一個函數增加一個型如PyObject* Mole_func()的包裝函數;c、為每個模塊增加一個型如PyMethodDef MoleMethods[]的數組;d、增加模塊初始化函數void initMole()。
2. 如何實現 C/C++ 與 Python 的通信
引入Python可以帶來更好的可調式性。且如果重負載應用使用C/C++則基本沒有性能損失,並可以讓工程師把更多精力放在演算法優化獲得性能優勢上。
簡單講Python與C/C++的直接交互就是兩種方向:C/C++寫擴展模塊給Python調用;將Python嵌入C/C++。題主說的是後者。而更方便方式是前者。因為內嵌方式決定了你整個交互部分開發完成之前沒法做測試。而擴展模塊方式則可以先行用Python快速開發出大部分功能,有需要性能優化的部分逐步優化到C/C++。是更加漸進式的過程。
直接用最基礎的方法寫擴展模塊略有繁雜,適合對細節的控制。題主時間緊迫則可以考慮Cython,可以在較短時間里完成些任務。但更多高級功能的玩法則限制很多。
其他交互方式還有多種,性能就不是那麼高了。比如fork()子進程,用管道通信。開獨立進程走mmap()交互,甚至是本機或其他機器上走socket。
最後,C++做了很多底層抽象,使得其與其他編程語言的互調用方面麻煩的要死。比較典型的包括類繼承,運算符重載,引用,其他還有太多。這些特性使得其他語言調用C++時各種惡心。這不僅僅是對Python,而是對所有語言都是如此。不信試試在C程序里調用一個C++運算符重載過的方法。所以,如非必要,盡量別用C++。用C簡單方便的多,而任何用以支持大規模項目的架構用Python就是了。
3. 命令行模式和Python交互模式有什麼區別
命令行模式是直接在命令行窗口中運行python的py文件,需要先用文本編輯器編寫代碼,再內通過命令行模式運行。交容互模式是執行一行就返回一行代碼的結果。
1、首先編寫一個py文件,然後打開cmd,輸入「python 文件路徑」就可以執行這個py文件。如下圖輸入的是「python 1.py」。這種就是命令行模式
4. 如何實現C/C++與Python的通信
這個可以稱之為兩個軟體(進程)之間的通信。
進程間通信主要包括管道, 系統IPC(包括消息內隊列容,信號量,共享存儲), SOCKET.
比如:你可以共同訪問計算機上的一個txt文件
也可以使用socket通信
也可以使用資料庫,
等等
都能達到通信的目的
5. 用python 去和c++程序交互,該看哪些知識點
從開始看Python到現在也有半個多月了,前後看了Python核心編程和Dive into
Python兩本書。話說半個月看兩本,是個人都知道有多囫圇吞棗,這也是因為我暫時沒有需求拿這個做大型開發,主要是平時的小程序test用一用。所以
我的策略是,整體瀏覽,用到時候現查。話說這核心編程第一版太古老了,老在講2.2之前的東西,我看的翻譯電子版,翻譯得也不好,很晦澀。看完這個後還有
點雲里霧里,看網上人家說DIP好,啄木鳥還有電子文檔,就找來看這個。怎麼說呢,講的比核心編程好,但不適合第一次看的初學者。我之所以覺得講得
好,是因為看核心編程,有些概念還有些模糊,看了這本書就明白不少了。要是初學者上來就看這本,保證不好理解。
下面就是在學習的過程中,在翻閱資料的過程中,總結的一些C和python比較明顯的不同之處,有大方向的,也有細節的。肯定沒有總結完,比如動態
函數,lambda這些,我都懶得往上寫了。實際上,作為兩種完全不同的語言,下面這些差異只是冰山一角而已。權當拋磚引玉吧,至少應該對和我有相同研究
興趣,正在考慮是否學習另一門語言的朋友有點幫助。此文也算是DIP的學習筆記吧。順帶說一句,要是有朋友了解,可以幫忙推薦一下實戰性強的Python
教材,語言這東西,不多練手,光比劃,是不可能學好的。
學習目的
我的以後的研究方向是嵌入式,顯然,C語言是我的主要語言。我不是一個語言愛好者,我以前覺得,對於做研究而不是應用的人來說,了解多門語言,不如
精通一門語言。之所以去看python,主要還是因為python更有利於快速開發一些程序,也是因為現在認識到,研究和應用是不能分離的。個人以為,要
想在計算機工程的競爭中立足,必須懂C語言。因為真正要做高性能編程,
不可能將機器的體系架構拋到腦後讓Python虛擬機(或java虛擬機等)幫你搞定所有底層。越來越多的CPU
core,越來越恐怖的內存性能瓶頸,對於上層開發人員來說,無所謂,但是對高性能程序開發人員來說,這些是無法透明的。很多應用,還是自己掌控比較有
效。這些場合中,匯編和C還是不可替代的。但是,光知道C是不夠的,掌握一門面向對象語言,相對更高層的語言,不僅對以後的個人發展有利,也會對自己的技
術認識產生幫助。
如果要問對我來說誰更重要,我覺得還是C更重要。C的學習曲線更陡,貌似簡單,實際上到處都是陷阱,看上去比較簡單低效的程序,也不是學1,2個月
就能搞定的。談到優化的深層次和難度嘛,需要的功底是按年算的。但是一旦你C語言的基礎打好了,對計算機的理解,對其他語言的理解都是大有裨益的。比如,
如果你有C基礎,可以說,學過1天python,就能寫的出來一些不短的程序。後面的優化也不是什麼大不了的演算法,都是非常基本的語句換來換去。當然這里
不是說 Python不好,實際上,上層應用,Python比C方便的不是一個層次。
很多人覺得,既然懂C了,那麼進一步掌握C++應該是水到渠成,但C++不是C的超集,而我又不喜歡C++的繁瑣和巨大,所以才決定看一看Python。我很喜歡Python的優雅與快捷。
語言類型
和C不一樣,Python是一種動態類型語言,又是強類型語言。這個分類怎麼理解呢?大概是可以按照下列說明來分類的:
靜態類型語言
一種在編譯期間就確定數據類型的語言。大多數靜態類型語言是通過要求在使用任一變數之前聲明其數據類型來保證這一點的。Java和 C 是靜態類型語言。
動態類型語言
一種在運行期間才去確定數據類型的語言,與靜態類型相反。Python 是動態類型的,因為它們確定一個變數的類型是在您第一次給它賦值的時候。
強類型語言
一種總是強制類型定義的語言。Java 和 Python 是強制類型定義的。您有一個整數,如果不明確地進行轉換 ,不能將把它當成一個字元串。
弱類型語言
一種類型可以被忽略的語言,與強類型相反。VBScript 是弱類型的。在 VBScript 中,您可以將字元串 『12′ 和整數 3 進行連接得到字元串』123′,然後可以把它看成整數 123 ,所有這些都不需要任何的顯示轉換。
對象機制
具體怎麼來理解這個「動態確定變數類型」,就要從Python的Object對象機制說起了。Objects(以下稱對象)是Python對於數據
的抽象,Python中所有的數據,都是由對象或者對象之間的關系表示的,函數是對象,字元串是對象,每個東西都是對象的概念。每一個對象都有三種屬性:
實體,類型和值。理解實體是理解對象中很重要的一步,實體一旦被創建,那麼就一直不會改變,也不會被顯式摧毀,同時通常意義來講,決定對象所支持的操作方
式的類型(type,包括number,string,tuple及其他)也不會改變,改變的只可能是它的值。如果要找一個具體點的說明,實體就相當於對
象在內存中的地址,是本質存在。而類型和值都只是實體的外在呈現。然後Python提供一些介面讓使用者和對象交互,比如id()函數用來獲得對象實體的
整形表示(實際在這里就是地址),type()函數獲取其類型。
這個object機制,就是c所不具備的,主要體現在下面幾點:
1 剛才說了,c是一個靜態類型語言,我們可以定義int a, char
b等等,但必須是在源代碼裡面事先規定。比如我們可以在Python裡面任意一處直接規定a =
「lk」,這樣,a的類型就是string,這是在其賦值的時候才決定的,我們無須在代碼中明確寫出。而在C裡面,我們必須顯式規定char *a =
「lk」,也就是人工事先規定好a的類型
2 由於在C中,沒有對象這個概念,只有「數據的表示」,比如說,如果有兩個int變數a和b,我們想比較大小,可以用a ==
b來判斷,但是如果是兩個字元串變數a和b,我們就不得不用strcmp來比較了,因為此時,a和b本質上是指向字元串的指針,如果直接還是用==比較,
那比較的實際是指針中存儲的值——地址。
在Java中呢,我們通過使用 str1 == str2 可以確定兩個字元串變數是否指向同一塊物理內存位置,這叫做「對象同一性」。在 Java 中要比較兩個字元串值,你要使用 str1.equals(str2)。
然後在Python中,和前兩者都不一樣,由於對象的引入,我們可以用「is」這個運算符來比較兩個對象的實體,和具體對象的type就沒有關系
了,比如你的對象是tuple也好,string也好,甚至class也好,都可以用」is」來比較,本質上就是「對象同一性」的比較,和Java中
的==類似,和 C中的pointer比較類似。Python中也有==比較,這個就是值比較了。
3
由於對象機制的引入,讓Python的使用非常靈活,比如我們可以用自省方法來查看內存中以對象形式存在的其它模塊和函數,獲取它們的信息,並對它們進行
操作。用這種方法,你可以定義沒有名稱的函數,不按函數聲明的參數順序調用函數,甚至引用事先並不知道名稱的函數。 這些操作在C中都是不可想像的。
4 還有一個很有意思的細節,就是類型對對象行為的影響是各方面的,比如說,a = 1; b =
1這個語句中,在Python裡面引發的,可能是a,b同時指向一個值為1的對象,也可能是分別指向兩個值為1的對象。而例如這個語句,c = []; d
= [],那麼c和d是肯定指向不同的,新創建的空list的。沒完,如果是」c = d =
[]「這個語句呢?此時,c和d又指向了相同的list對象了。這些區別,都是在c中沒有的。
最後,我們來說說為什麼python慢。主要原因就是function call
overhead比較大。因為所有東西現在都是對象了,contruct 和destroy 花費也大。連1 + 1 都是 function
call,像』12′+』45′ 這樣的要 create a third string object, then calls the string
obj』s __add。可想而知,速度如何能快起來?
列表和數組
分析Python中的list和C中的數組總是很有趣的。相信可能一些朋友和一樣,初學列表的時候,都是把它當作是數組來學的。最初對於list和數組區別的定性,主要是集中在兩點。首先,list可以包含很多不同的數據類型,比如
["this", 1, "is", "an", "array"]
這個List,如果放在C中,其實是一個字元串數組,相當於二維的了。
其次呢,list有很多方法,其本身就是一個對象,這個和C的單純數組是不同的。對於List的操作很多樣,因為有方法也有重載的運算符。也帶來一些問題,比如下面這個例子:
加入我們要產生一個多維列表,用下面這個語句
A = [[None] * 2] * 3
結果,A的值會是
[[None, None], [None, None], [None, None]]
初一看沒問題,典型的二維數組形式的列表。好,現在我們想修改第一個None的值,用語句
A[0][0] = 5
現在我們再來看看A的值:
[[5, None], [5, None], [5, None]]
發現問題沒有?這是因為用 * 來復制時,只是創建了對這個對象的引用,而不是真正的創建了它。 *3 創建了一個包含三個引用的列表,這三個引用都指向同一個長度為2的列表。其中一個行的改變會顯示在所有行中,這當然不是你想要的。解決方法當然有,我們這樣來創建
A = [None]*3
for i in range(3):
A[i] = [None] * 2
這樣創建了一個包含三個不同的長度為2的列表。
所以,還是一直強調的,越復雜的東西,越靈活,也越容易出錯。
代碼優化
C是一個很簡單的語言,當我們考慮優化的時候,通常想得也很簡單,比如系統級調用越少越好(緩沖區機制),消除循環的低效率和不必要的系統引用,等
等,其實主要都是基於系統和硬體細節考慮的。而Python就完全不一樣了,當然上面說的這些優化形式,對於Python仍然是實用的,但由於
Python的語法形式千差萬別,庫和模塊多種多樣,所以對於語言本身而言,就有很多值得注意的優化要點,舉幾個例子吧。
比如我們有一個list L1,想要構建一個新的list L2,L2包括L1的頭4個元素。按照最直接的想法,代碼應該是
L2 = []
for i in range[3]:
L2.append(L1[i])
而更加優化和優美的版本是
L2 = L1[:3]
再比如,如果s1..s7是大字元串(10K+),那麼join([s1,s2,s3,s4,s5,s6,s7])就會比
s1+s2+s3+s4+s5+s6+s7快得多,因為後者會計算很多次子表達式,而join()則在一次過程中完成所有的復制。還有,對於字元串操作,
對字元串對象使用replace()方法。僅當在沒有固定字元串模式時才使用正則表達式。
所以說,以優化為評判標准,如果說C是短小精悍,Python就是博大精深。
include和import
在C語言中的include非常簡單,因為形式單一,意義明確,當你需要用到外部函數等資源時,就用include。而Python中有一個相似的
機制,就是import。乍一看,這兩個傢伙挺像的,不都是我們要用外部資源(最常見的就是函數或者模塊(Python))時就用這個來指明么?其實不
然,兩者的處理機制本質區別在於,C中的include是用於告訴預處理器,這個include指定的文件的內容,你都給我當作在本地源文件中出現過。而
import呢,不是簡單的將後面的內容*直接*插入到本地裡面去,這玩意更加靈活。事實上,幾乎所有類似的機制,Python都比C靈活。這里不是說C
不好,C很簡練,我其實更喜歡C。
簡單說說這個靈活性。import在python中有三種形式,import X, from X import *( or a,b,c……),
X = __import__(』x')。最常用的是第二種,因為比較方便,不像第一種那樣老是用X.mole來調用模塊。from X
import *只是import那些public的mole(一般都是不以__命名的模塊),也可以指定a,b,c來import。
什麼時候用哪一種形式呢?應該說,在大多數的模塊文檔里,都會明確告訴你應該用哪種形式。如果需要用到很多對象,那麼from X import
*可能更合適一些,但是,就目前來看,大多數第三方Python庫都不推薦使用from molename import *
這種格式。這樣做會使引入者的namespace混亂。很多人甚至對於那些專門設計用於這種模式的模塊(包括Tkinter,
threading和matplot)都不採用這種方式。而如果你僅僅需要某個對象類a,那麼用from X import a比用import
X.a更好,因為以後你調用a的函數直接用a.function()既可以了,不用加X。
如果你連自己希望import的模塊都不知道怎麼辦?請注意,此時Python的優勢就體現出來了,我們可以用
__import__(mole)來調用mole,其中這個mole是字元串,這樣,可以在運行時再決定,你到底要調用什麼mole。舉
個例子:
def classFromMole (mole, Name):
mod = __import__ (mole)
return getattr (mod, Name)
這里,定義了一個函數classFromMole,你可以在代碼的任何時候調用它,
o = classFromMole (MoleOfTheClass, NameOfTheAttribute)()
只需要傳入字元串形式的你希望import的模塊MoleOfTheClass和其中屬性的名字NameOfTheAttribute(當然可以是數據也可以是方法),就能調用了,這個名字字元串不用事先指定,而是根據當時運行的情況來判斷。
順帶說一句,Python中import的順序也有默認規定,這個和C中的include有點類似,因為我們一般都是先include系統文件,再
include自己的頭文件(而且還有<>和「」的區別)。Python中呢,一般應該按照以下順序import模塊:
1. 標准庫模塊 — 如 sys, os, getopt 等
2. 第三方模塊
3. 本地實現的模塊。
全局變數
這里談全局變數呢,倒不是說Python和c的全局變數概念不同,他們的概念是相同的。只是在使用機制上,是有一些差異的。舉個例子:
– mole.py –
globalvar = 1
def func():
print globalvar
# This makes someglobal readonly,
# any attempt to write to someglobal
# would create a new local variable.
def func2():
global globalvar
globalvar = 2
# this allows you to manipulate the global
# variable
在 func這個函數中,globalvar是只讀的。如果你使用了globalvar =
xxx這種賦值語句,Python會重新創造一個新的本地對象並將新值賦給它,原來的對象值不變。而在func2函數中,由於我們事先申明了
globalvar是global的,那麼此時的更改就直接在全局變數上生效。
6. js 和 python怎麼交互
python取得javascript裡面的值
復制代碼代碼如下:
import PyV8
with PyV8.JSContext() as env1:
env1.eval("""
var_i = 1;
var_f = 1.0;
var_s = "test";
var_b = true;
""")
vars = env1.locals
var_i = vars.var_i
print var_i
javascript取得python裡面的值
復制代碼代碼如下:
import PyV8
with PyV8.JSContext() as env1:
env1.securityToken = "foo"
env1.locals.prop = 3
print int(env1.eval("prop"))
python和javascript裡面的函數交互
python調用javascript裡面的函數python調用func就可以使用js裡面的function函數了
復制代碼代碼如下:
import PyV8
with PyV8.JSContext() as ctxt:
func = ctxt.eval("""
(function ()
{
function a()
{
return "abc";
}
return a();
})
""")
print func()
這樣也可以
復制代碼代碼如下:
import PyV8
with PyV8.JSContext() as ctxt:
func = ctxt.eval("""
function a()
{
return "abc";
}
function c()
{
return "abc";
}
""")
a = ctxt.locals.a
print a()
7. 如何讓python調用C和C++代碼
如何讓python調用和C++代碼
安裝python後,會有一個chm格式的python手冊。要搞明白如何讓python調用C/C++代碼(也就是寫python的 extension),你需要征服手冊中的
<<Extending && embedding>>厚厚的一章。在昨天花了一個小時看地頭暈腦脹,仍然不知道如何寫python的extension後,查閱了一些其他 書籍,最終在<<Python Programming On Win32>>書中找到了教程。
下面記錄一下如何在visual studio 2005中,寫一段C/C++的MessageBox代碼,然後提供後python調用,最後的結果當然是顯示一個MessageBox.
1. 首先要明白的是,所謂的python擴展(也就是你提供給python的c/c++代碼,不一定是c/c++代碼,可以是其他語言寫的代碼)是一個 dll,並且這個dll放在本機python安裝目錄下的DLLs目錄下(譬如我機器上的路徑是:F:\Program Files\Python25\DLLs),假如我們接下來要寫的擴展mole名為mb,python調用的代碼為: import mb
mb.showMsg("Python's really amazing, I kindda love it!")
python怎麼找到我們的mb模塊呢?就是上面說的,我們要生成一個mb.dll,然後拷貝到Dlls目錄下面,為了區別普通的dll和python專用擴展的dll,我們的 mb.dll修改成mb.pyd(python dll)
2. 搭建環境,我們要使用python提供的c頭文件和lib庫來進行擴展的開發。 在vs 2005下點擊菜單 "工具"->"選項", 打開選項對話框,選擇"項目和解決方案->VC++目錄", 然後在右邊"顯示以下內容的目錄"得comboBox上選擇"包含文件」,添加python的include目錄(我的機器上是"F:\Program
Files\Python25\include"),然後選擇庫文件,添加python的libs目錄(我的機器上是"F:\Program Files\Python25\libs")。
既然擴展是一個dll,接下來我們要建立一個「動態鏈接庫」工程,然後開始寫代碼:
#include <python.h> //python.h是包含python一些定義的頭文件,在python的include目錄下 /*
我的python版本是2.5, 因為安裝python後它沒提供debug下的lib庫文件,因此你必須生成release版的dll,
想要生成dll版本的,你要到python官網上自己去下載python源代碼,當然你可以繼續生成release版本的dll,但dll中包含調試信息
*/
#pragma comment(lib, "python25.lib")
//先不管
static PyObject* mb_showMsg(PyObject* self, PyObject *args); /*
如果你的擴展是mb,那麼必須實現一個initmb函數,並且從dll中導出這個函數,但我們在python中調用import mb時,python會去dll里去調用
initmb函數,這個函數告訴python我們有些什麼函數,該怎麼告訴python我們有一個showMsg函數呢?下面詳解 */
//必須extern "C"下,這樣不會在C++編譯器里不會更改掉導出的函數名字,我第一次就犯了這樣的錯誤
extern "C" __declspec(dllexport) void initmb() { /*
當調用mb.showMsg("Python's really amazing, I kindda love it!")時, 相當於你告訴python我有一個showMsg函數,我們怎麼告訴python去調用我們dll里的mb_showMsg函數呢?技巧就是下面的方式, 定義一個字典數據結構,key => showMsg, value =>mb_showMsg,METH_VARARGS是函數調用方式,仔細查手冊吧 */
static PyMethodDef mbMethods[] = { {"showMsg", mb_showMsg, METH_VARARGS},
{NULL, NULL, NULL} /*sentinel,哨兵,用來標識結束*/ };
//告訴python我們的模塊名叫mb, 模塊包含的函數都在mbMethods字典里 PyObject *m = Py_InitMole("mb", mbMethods); } /*
接下來實現核心功能showMsg */
//第一個self參數我們用不著,具體查手冊,第二個參數是python傳給我們的參數,它是一個python的參數tuple
static PyObject* mb_showMsg(PyObject* self, PyObject *args) {
//我們的showMsg函數需要的是一個字元串參數 const char* msg = NULL; /*
調用特殊參數解碼python傳遞給我們的參數,s是string,我們傳遞接收參數的變數地址,
如果你的功能函數需要兩個參數,在PyArg_parseTuple後面繼續添加接受參數的變數地址,
這個函數的原型是類似printf的不定參數的形式
PyAPI_FUNC(int) PyArg_ParseTuple(PyObject *, const char *, ...); */
if (!PyArg_ParseTuple(args, "s", &msg)) return NULL;
//調用MB
int r = ::MessageBox(NULL, "hello", "Caption:Form C mole", MB_ICONINFORMATION | MB_OK);
//返回值
return Py_BuildValue("i", r); }
將上面這段混雜著大量注釋的代碼拷貝到你的編輯器里,然後編譯生成mb.dll,修改後綴成mb.pyd,然後拷貝到python的DLLs目錄下,打開idle(python的交互程序),寫入代碼: import mb
mb.showMsg("Python's really amazing, I kindda love it!")
可以看到彈出來一個MessageBox。