淺析Python中的struct模組

來源:互聯網
上載者:User

標籤:dex   style   pad   環境   idt   forms   結構   解決   ref   

最近在學習python網路編程這一塊,在寫簡單的socket通訊代碼時,遇到了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.)。stuct模組提供了很簡單的幾個函數,下面寫幾個例子。

1、基本的pack和unpack

    struct提供用format specifier方式對資料進行打包和解包(Packing and Unpacking)。例如:

123456789101112 import structimport binasciivalues = (1, ‘abc‘, 2.7)s = struct.Struct(‘I3sf‘)packed_data = s.pack(*values)unpacked_data = s.unpack(packed_data) print ‘Original values:‘, valuesprint ‘Format string :‘, s.formatprint ‘Uses :‘, s.size, ‘bytes‘print ‘Packed Value :‘, binascii.hexlify(packed_data)print ‘Unpacked Type :‘, type(unpacked_data), ‘ Value:‘, unpacked_data

輸出:

Original values: (1, ‘abc‘, 2.7) 
Format string : I3sf 
Uses : 12 bytes 
Packed Value : 0100000061626300cdcc2c40 
Unpacked Type : <type ‘tuple‘>  Value: (1, ‘abc‘, 2.700000047683716)

代碼中,首先定義了一個元組資料,包含int、string、float三種資料類型,然後定義了struct對象,並制定了format‘I3sf’,I 表示int,3s表示三個字元長度的字串,f 表示 float。最後通過struct的pack和unpack進行打包和解包。通過輸出結果可以發現,value被pack之後,轉化為了一段二進位位元組串,而unpack可以把該位元組串再轉換回一個元組,但是值得注意的是對於float的精度發生了改變,這是由一些比如作業系統等客觀因素所決定的。打包之後的資料所佔用的位元組數與C語言中的struct十分相似。定義format可以參照官方api提供的對照表:

2、位元組順序

   另一方面,打包的後的位元組順序預設上是由作業系統的決定的,當然struct模組也提供了自訂位元組順序的功能,可以指定大端儲存、小端儲存等特定的位元組順序,對於底層通訊的位元組順序是十分重要的,不同的位元組順序和儲存方式也會導致位元組大小的不同。在format字串前面加上特定的符號即可以表示不同的位元組順序儲存方式,例如採用小端儲存 s = struct.Struct(‘<I3sf’)就可以了。官方api library 也提供了相應的對照列表:

3、利用buffer,使用pack_into和unpack_from方法

  使用二進位打包資料的情境大部分都是對效能要求比較高的使用環境。而在上面提到的pack方法都是對輸入資料進行操作後重新建立了一個記憶體空間用於返回,也就是說我們每次pack都會在記憶體中分配出相應的記憶體資源,這有時是一種很大的效能浪費。struct模組還提供了pack_into() 和 unpack_from()的方法用來解決這樣的問題,也就是對一個已經提前分配好的buffer進行位元組的填充,而不會每次都產生一個新對象對位元組進行儲存。

123456789101112 import structimport binasciiimport ctypes values = (1, ‘abc‘, 2.7)s = struct.Struct(‘I3sf‘)prebuffer = ctypes.create_string_buffer(s.size)print ‘Before :‘,binascii.hexlify(prebuffer)s.pack_into(prebuffer,0,*values)print ‘After pack:‘,binascii.hexlify(prebuffer)unpacked = s.unpack_from(prebuffer,0)print ‘After unpack:‘,unpacked

輸出:

Before : 000000000000000000000000 
After pack: 0100000061626300cdcc2c40 
After unpack: (1, ‘abc‘, 2.700000047683716) 
對比使用pack方法打包,pack_into 方法一直是在對prebuffer對象進行操作,沒有產生多餘的記憶體浪費。另外需要注意的一點是,pack_into和unpack_from方法均是對string buffer對象進行操作,並提供了offset參數,使用者可以通過指定相應的offset,使相應的處理變得更加靈活。例如,我們可以把多個對象pack到一個buffer裡面,然後通過指定不同的offset進行unpack:

12345678910111213141516 import structimport binasciiimport ctypes values1 = (1, ‘abc‘, 2.7)values2 = (‘defg‘,101)s1 = struct.Struct(‘I3sf‘)s2 = struct.Struct(‘4sI‘) prebuffer = ctypes.create_string_buffer(s1.size+s2.size)print ‘Before :‘,binascii.hexlify(prebuffer)s1.pack_into(prebuffer,0,*values1)s2.pack_into(prebuffer,s1.size,*values2)print ‘After pack:‘,binascii.hexlify(prebuffer)print s1.unpack_from(prebuffer,0)print s2.unpack_from(prebuffer,s1.size)

輸出:

Before : 0000000000000000000000000000000000000000 
After pack: 0100000061626300cdcc2c406465666765000000 
(1, ‘abc‘, 2.700000047683716) 
(‘defg‘, 101)

淺析Python中的struct模組

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.