Python 在 ctypes 中為我們提供了類似C語言的數據類型,
它的用途(我理解的)可能是:
(1) 與 其他語言(如 C、Delphi 等)寫的動態連接庫DLL 進行交換數據,因為 python 的 數據與 DLL難以進行數據交換。
(2) python 的字符串一旦形成,是不可變的,為了算法的需要,我們有時需要對字符串進行原位操作 ( in place ),而不想浪費另外的內存空間。
(3) python 具有很簡明的語法,人們樂於使用。在解決實際問題時,字符串的處理占據了很大的開發量。
互聯網上有很多有用的算法可以幫助我們解決問題,如果我們能用python 寫類似於 C 語言的程序,就不需要用其他語去寫擴展了。
有人會問,既然如此,用C語言,不就好了嗎?
當然可作這種選擇,在用 python 的優勢在於:既用使用了C語言的優點,也使用了Python的最大優點: 垃圾自動回收,代碼簡潔等。
一、 導入 C 類型 庫
from ctypes import *
二、 常用的C 類型
(1) c_int 、 c_long 、c_int32
C 類型的long int ,這兩個類型完全相同。
python 用 int 與之相應 , 但c_int的取值范圍是 32 bit 的整數 。
占用 4 字節內存
(2) c_int64
64 bit 整數,占用 8 字節內存 , python 用 int 與之相應
(2) c_double 、c_float
C 類型的 double , 這兩個名字( c_double 、c_float 完全相同 )
占用 8 字節內存
python 用 float 與之相應
(3) c_byte
C 類型 的 byte , python 用 int 與之相應
占用1字節內存
(4) c_char
C 的 8 bit 字符型
(5) c_wchar
C 的 unicode 字符
【注】
ctypes模塊 C類型 Python類型 ctypes 類型 當一個函數期望一個指針作為參數時,可以像這樣調用 struct例子 Python例子 |
三、 生成類似C的數組
目的:初值化一個具有 10 個元素 的數組,每個元素初值為0的
(一) python 原生數組 list
>>> a = [ 0 ] * 10
>>> for i in range(0, len(a)):
print( a[i], end=" ")
0 0 0 0 0 0 0 0 0 0
>>>
(二) 生成 10 元素的 c_int 類型的數組:
格式一:
>>> from ctypes import *
>>> a = ( c_int * 10) ()
>>> for i in range(0, len(a)):
print( a[i], end=" ")
0 0 0 0 0 0 0 0 0 0
>>>
格式二:
>>> from ctypes import *
>>> M = 10
>>> a = ( c_int * M ) ()
>>> for i in range(0, len(a)):
print( a[i], end=" ")
0 0 0 0 0 0 0 0 0 0
格式三:
>>> from ctypes import *
>>> myArr10 = c_int * 10
>>> a = myArr10( )
>>> for i in range(0, len(a)):
print( a[i], end=" ")
0 0 0 0 0 0 0 0 0 0
c_double 的數組定義與上面相似。
四、如何使用 C 類型的數組 ?
例 1 , 對整數數組倒序的程序
#coding=gbk
from ctypes import *
# 定義 具有10個 c_int 元素的數組
# 編寫一維數組的 倒序的程序
# 說明 : 本算法參照 網上基於指針的算法改寫而成。
def outPut( A ):
for i in range(0,N):
print( A[i], end=" ")
print ( "\n")
def arrReverse( A , N):
i = 0 ; j = N-1
while i<j:
A[i], A[j] = A[j], A[i]
# 相當於 T =A[i]; A[i]=A[j]; A[j]=T
i = i+1; j=j-1
#測試程序
N = 10
a = (c_int * N )()
for i in range(0,N):
a[i] = i;
print ( "原數組:")
outPut( a )
arrReverse( a ,len(a) )
print ("倒序數組:")
outPut( a )
--- 結果 ---
原數組:
0 1 2 3 4 5 6 7 8 9
倒序數組:
9 8 7 6 5 4 3 2 1 0
例2 求倒序字符串
#coding=gbk
from ctypes import *
# 編寫求字符串的倒序字符串
def arrReverse( A , N ):
i = 0 ; j = N-1
while i<j:
A[i], A[j] = A[j], A[i]
# 相當於 T =A[i]; A[i]=A[j]; A[j]=T
i = i+1; j=j-1
#測試程序
a = create_unicode_buffer( "張三買了一頭小毛驢,花了1024.05元錢。")
print ( "原字符:")
print ( a.value )
arrReverse( a , len( a ) -1 )
print ("倒序字符串:")
print ( a.value )
-- 結果 --
原字符:
張三買了一頭小毛驢,花了1024.05元錢。
倒序字符串:
。錢元50.4201了花,驢毛小頭一了買三張
解說
(1) create_unicode_buffer( python的字符串 )
是創建一個 c_wchar 的數組,其長度是 字符串的長度 +1 , 因為 C 的字符串是以 NULL 結尾的所以要多出一個元素才行。
c_wchar 是 unicode 字符。
(2) 如果您想創建一個可以裝行下 100 個 unicode 字符 的空的C_wchar 數組:
ar = create_unicode_buffer( 100+1 )
此時, ar 具有 101 個元素,但只能裝 100個字符。
由於 ar 是一個真正的數組,我們可以對它的每個元素(字符)進行修改。
從 ar 中取出 python 的字符串:
s = ar.value
s 中存放的是 ar 中保存的 unicode 字符相應的字符串
向 ar 中存於字符串
ar.value = "要存入的字符串"
但要注意:
您向 ar 中存入的字符串的字符個數必須小於等於 len(ar) -1
(3) 如果您知道 ar 中第 i 個元素的 字符編碼,請使用 ord( ar[i] ) .
(4) 如果您想使 ar 的第 i 個元素 變為 "好" 這個字符,有兩種方法:
ar[i] = "好"
或者
ar[i] = chr(22909)
因為 , "好" 的 uncode 編碼是 22909。
小結:
(1) 從這個程序我們看到 對整數數組及 unicode 字符數組 的倒序,我們用的是相同的arrReverse 函數。
(2) 調用 arrReverse
函數時,傳遞元素個數 N 時,如果是 c_wchar ( unicode ) 字符數組時, 如記住最后一個元素是 NULL 這個問題。
( 3 ) 您會發現,我們這里編的程序很像 C 語言的指針,只不過,我們不需要手工釋放動態申請的數組。
( 4 ) 但是您的算法中若用了大量的動態數組,等不及垃圾自動回收,而急於想釋放數組占用的空間時,請使用 del ( ar )即可。
( 5) 最后一點:
C 語言關於字符串的操作,常 使用指針的移動, 我們在 python 中移動的是數組的下標,這是作程序移植時常用的方法。
五、 C類型的數組 與 python 的 list 用法上有什么區別和聯系呢?
1 C 類型的數組的長度是不可變 的。
2 C 類型數組的元素是可變的,即可以讀寫的
3 C 類型數組的元素是有類型的,即: 它的每個元素的類型是相同的, 而 python 的 list 的元素可以是相同類型,也可以是不同類型 。
4 C 類型數組除了不能用 形如 ar[ 3:5 ] = [] 格式的語句來刪除某個子數組
5 C 類型數組的切片:
如 x = ar[3:5]
此時 x 是一個全新的 數組,它是原數組的完全拷貝, 此時 x 有兩個元素:
x[0] 中存的是 ar[3]的值
x[1] 中存的是 ar[4]的值
此后,改變 x[0] 時, ar[3] 不會改變; 改變 ar[3] 的值,也不會改變 x[0] 的值。