1. 程式人生 > >Python中的struct模組

Python中的struct模組

Python是一門非常簡潔的語言,對於資料型別的表示,不像其他語言預定義了許多型別(如:在C#中,光整型就定義了8種),它只定義了六種基本型別:字串,整數,浮點數,元組,列表,字典。通過這六種資料型別,我們可以完成大部分工作。但當Python需要與其他的平臺(其他的程式語言)進行互動的時候,必須考慮到將這些資料型別與其他平臺或語言之間的型別進行互相轉換問題。打個比方:C++寫的客戶端傳送一個int型(4位元組)變數的資料到Python寫的伺服器,Python接收到表示這個整數的4個位元組資料,怎麼解析成Python認識的整數呢? Python的標準模組struct就用來解決這個問題。

瞭解c語言的人,一定會知道struct結構體在c語言中的作用,它定義了一種結構,裡面包含不同型別的資料(int,char,bool等等),方便對某一結構物件進行處理。而在網路通訊當中,大多傳遞的資料是以二進位制流(binary data)存在的。當傳遞字串時,不必擔心太多的問題,而當傳遞諸如int、char之類的基本資料的時候,就需要有一種機制將某些特定的結構體型別打包成二進位制流的字串然後再網路傳輸,而接收端也應該可以通過某種機制進行解包還原出原始的結構體資料。python中的struct模組就提供了這樣的機制,該模組的主要作用就是對python基本型別值與用python字串格式表示的C struct型別間的轉化(This module performs conversions between Python values and C structs represented as Python strings.)。


struct模組的內容不多,也不是太難,下面對其中最常用的方法進行介紹,struct模組中最重要的三個函式是pack(), unpack(), calcsize()
  • pack(fmt, v1, v2, ...)     按照給定的格式(fmt),把資料封裝成字串(實際上是類似於c結構體的位元組流)
  • unpack(fmt, string)       按照給定的格式(fmt)解析位元組流string,返回解析出來的tuple
  • calcsize(fmt)                 計算給定的格式(fmt)佔用多少位元組的記憶體

struct.pack

struct.pack用於將Python的值根據格式符,轉換為字串(因為Python中沒有位元組(Byte)型別,可以把這裡的字串理解為位元組流,或位元組陣列)。其函式原型為:struct.pack(fmt, v1, v2, …),引數fmt是格式字串,關於格式字串的相關資訊在下面有所介紹。v1, v2, …表示要轉換的python值。下面的例子將兩個整數轉換為字串(位元組流):

import struct
 
a = 20
b = 400
 
str = struct.pack("ii", a, b)  #轉換後的str雖然是字串型別,但相當於其他語言中的位元組流(位元組陣列),可以在網路上傳輸
print 'length:', len(str)
print str
print repr(str)

格式符”i”表示轉換為int,’ii’表示有兩個int變數。進行轉換後的結果長度為8個位元組(int型別佔用4個位元組,兩個int為8個位元組),可以看到輸出的結果是亂碼,因為結果是二進位制資料,所以顯示為亂碼。可以使用python的內建函式repr來獲取可識別的字串,其中十六進位制的0x00000014, 0x00001009分別表示20和400。

struct模組定義的資料型別表:


struct.unpack

struct.unpack做的工作剛好與struct.pack相反,用於將位元組流轉換成python資料型別。它的函式原型為:struct.unpack(fmt, string),該函式返回一個元組。 下面是一個簡單的例子:
str = struct.pack("ii", 20, 400)
a1, a2 = struct.unpack("ii", str)
print 'a1:', a1
print 'a2:', a2

struct.calcsize

struct.calcsize用於計算格式字串所對應的結果的長度,如:struct.calcsize(‘ii’),返回8。因為兩個int型別所佔用的長度是8個位元組。

一個例子

# -*- coding: utf-8 -*-

import struct

# 定義資料
a = "hello"
b = "world!"
c = 20
d = 42.56

# 打包
binStr = struct.pack("5s6sif", a, b, c, d)
print len(binStr)
binStr2 = struct.pack("i", c)

# 解包
e, f, g, h = struct.unpack("5s6sif", binStr)
print e, f, g, h

i, = struct.unpack("i", binStr2)
print i

# 計算轉換位元組長度
print struct.calcsize("5s6sif")
輸出結果:
20
hello world! 20 42.5600013733
20
20