Python标准库笔记(6) — struct模块
该模块作用是完成Python数值和C语言结构体的Python字符串形式间的转换。这可以用于处理存储在文件中或从网络连接中存储的二进制数据,以及其他数据源。
用途: 在Python基本数据类型和二进制数据之间进行转换
struct模块提供了用于在字节字符串和Python原生数据类型之间转换函数,比如数字和字符串。
模块函数和Struct类
它除了提供一个Struct类之外,还有许多模块级的函数用于处理结构化的值。这里有个格式符(Format specifiers)的概念,是指从字符串格式转换为已编译的表示形式,类似于正则表达式的处理方式。通常实例化Struct类,调用类方法来完成转换,比直接调用模块函数有效的多。下面的例子都是使用Struct类。
Packing(打包)和Unpacking(解包)
Struct支持将数据packing(打包)成字符串,并能从字符串中逆向unpacking(解压)出数据。
在本例中,格式指定器(specifier)需要一个整型或长整型,一个两个字节的string,和一个浮点数。格式符中的空格用于分隔各个指示器(indicators),在编译格式时会被忽略。
import struct
import binascii
values = (1, 'ab'.encode('utf-8'), 2.7)
s = struct.Struct('I 2s f')
packed_data = s.pack(*values)
print('原始值:', values)
print('格式符:', s.format)
print('占用字节:', s.size)
print('打包结果:', binascii.hexlify(packed_data))
# output
原始值: (1, b'ab', 2.7)
格式符: b'I 2s f'
占用字节: 12
打包结果: b'0100000061620000cdcc2c40'
这个示例将打包的值转换为十六进制字节序列,用binascii.hexlify()方法打印出来。
使用unpack()方法解包。
import struct
import binascii
packed_data = binascii.unhexlify(b'0100000061620000cdcc2c40')
s = struct.Struct('I 2s f')
unpacked_data = s.unpack(packed_data)
print('解包结果:', unpacked_data)
# output
解包结果: (1, b'ab', 2.700000047683716)
将打包的值传给unpack(),基本上返回相同的值(浮点数会有差异)。
字节顺序/大小/对齐
默认情况下,pack是使用本地C库的字节顺序来编码的。格式化字符串的第一个字符可以用来表示填充数据的字节顺序、大小和对齐方式,如下表所描述的:
| Character | Byte order | Size | Alignment |
|---|---|---|---|
@ |
本地 | 本地 | 本地 |
= |
本地 | standard | none |
< |
little-endian(小字节序) | standard | none |
> |
big-endian(大字节序) | standard | none |
! |
network (= big-endian) | standard | none |
如果格式符中没有设置这些,那么默认将使用 @。
本地字节顺序是指字节顺序是由当前主机系统决定。比如:Intel x86和AMD64(x86-64)使用小字节序; Motorola 68000和 PowerPC G5使用大字节序。ARM和Intel安腾支持切换字节序。可以使用sys.byteorder查看当前系统的字节顺序。
本地大小(Size)和对齐(Alignment)是由c编译器的sizeof表达式确定的。它与本地字节顺序对应。
标准大小由格式符确定,下面会讲各个格式的标准大小。
示例:
import struct
import binascii
values = (1, 'ab'.encode('utf-8'), 2.7)
print('原始值 : ', values)
endianness = [
('@', 'native, native'),
('=', 'native, standard'),
('<', 'little-endian'),
('>', 'big-endian'),
('!', 'network'),
]
for code, name in endianness:
s = struct.Struct(code + ' I 2s f')
packed_data = s.pack(*values)
print()
print('格式符 : ', s.format, 'for', name)
print('占用字节: ', s.size)
print('打包结果: ', binascii.hexlify(packed_data))
print('解包结果: ', s.unpack(packed_data))
# output
原始值 : (1, b'ab', 2.7)
格式符 : b'@ I 2s f' for native, native
占用字节: 12
打包结果: b'0100000061620000cdcc2c40'
解包结果: (1, b'ab', 2.700000047683716)
格式符 : b'= I 2s f' for native, standard
占用字节: 10
打包结果: b'010000006162cdcc2c40'
解包结果: (1, b'ab', 2.700000047683716)
格式符 : b'< I 2s f' for little-endian
占用字节: 10
打包结果: b'010000006162cdcc2c40'
解包结果: (1, b'ab', 2.700000047683716)
格式符 : b'> I 2s f' for big-endian
占用字节: 10
打包结果: b'000000016162402ccccd'
解包结果: (1, b'ab', 2.700000047683716)
格式符 : b'! I 2s f' for network
占用字节: 10
打包结果: b'000000016162402ccccd'
解包结果: (1, b'ab', 2.700000047683716)
格式符
格式符对照表如下:
| Format | C Type | Python type | Standard size | Notes |
|---|---|---|---|---|
x |
pad byte | no value | ||
c |
char |
bytes of length 1 | 1 | |
b |
signed char |
integer | 1 | (1),(3) |
B |
unsigned char |
integer | 1 | (3) |
? |
_Bool |
bool | 1 | (1) |
h |
short |
integer | 2 | (3) |
H |
unsigned short |
integer | 2 | (3) |
i |
int |
integer | 4 | (3) |
I |
unsigned int |
integer | 4 | (3) |
l |
long |
integer | 4 | (3) |
L |
unsigned long |
integer | 4 | (3) |
q |
long long |
integer | 8 | (2), (3) |
Q |
unsigned long long |
integer | 8 | (2), (3) |
n |
ssize_t |
integer | (4) | |
N |
size_t |
integer | (4) | |
f |
float |
float | 4 | (5) |
d |
double |
float | 8 | (5) |
s |
char[] |
bytes | ||
p |
char[] |
bytes | ||
P |
void * |
integer | (6) |
缓冲区
将数据打包成二进制通常是用在对性能要求很高的场景。
在这类场景中可以通过避免为每个打包结构分配新缓冲区的开销来优化。
pack_into()和unpack_from()方法支持直接写入预先分配的缓冲区。
import array
import binascii
import ctypes
import struct
s = struct.Struct('I 2s f')
values = (1, 'ab'.encode('utf-8'), 2.7)
print('原始值:', values)
print()
print('使用ctypes模块string buffer')
b = ctypes.create_string_buffer(s.size)
print('原始buffer :', binascii.hexlify(b.raw))
s.pack_into(b, 0, *values)
print('打包结果写入 :', binascii.hexlify(b.raw))
print('解包 :', s.unpack_from(b, 0))
print()
print('使用array模块')
a = array.array('b', b'\0' * s.size)
print('原始值 :', binascii.hexlify(a))
s.pack_into(a, 0, *values)
print('打包写入 :', binascii.hexlify(a))
print('解包 :', s.unpack_from(a, 0))
# output
原始值: (1, b'ab', 2.7)
使用ctypes模块string buffer
原始buffer : b'000000000000000000000000'
打包结果写入 : b'0100000061620000cdcc2c40'
解包 : (1, b'ab', 2.700000047683716)
使用array模块
原始值 : b'000000000000000000000000'
打包写入 : b'0100000061620000cdcc2c40'
解包 : (1, b'ab', 2.700000047683716)
博客原文: http://www.spiderpy.cn/blog/detail/37
Python标准库笔记(6) — struct模块的更多相关文章
- Python标准库笔记(8) — pprint模块
struct模块提供了用于在字节字符串和Python原生数据类型之间转换函数,比如数字和字符串. Python版本: 2.x & 3.x 该模块作用是完成Python数值和C语言结构体的Pyt ...
- Python标准库笔记(11) — Operator模块
Operator--标准功能性操作符接口. 代码中使用迭代器时,有时必须要为一个简单表达式创建函数.有些情况这些函数可以用一个lambda函数实现,但是对于某些操作,根本没必要去写一个新的函数.因此o ...
- Python标准库笔记(10) — itertools模块
itertools 用于更高效地创建迭代器的函数工具. itertools 提供的功能受Clojure,Haskell,APL和SML等函数式编程语言的类似功能的启发.它们的目的是快速有效地使用内存, ...
- Python标准库笔记(9) — functools模块
functools 作用于函数的函数 functools 模块提供用于调整或扩展函数和其他可调用对象的工具,而无需完全重写它们. 装饰器 partial 类是 functools 模块提供的主要工具, ...
- Python 标准库笔记(1) — String模块
原文出处: j_hao104 String模块包含大量实用常量和类,以及一些过时的遗留功能,并还可用作字符串操作. 1. 常用方法 常用方法 描述 str.capitalize() 把字符串的首字母大 ...
- (转)Python 标准库笔记:string模块
String模块包含大量实用常量和类,以及一些过时的遗留功能,并还可用作字符串操作. 原文:http://www.10tiao.com/html/384/201709/2651305041/1.htm ...
- Python标准库笔记(1) — string模块
String模块包含大量实用常量和类,以及一些过时的遗留功能,并还可用作字符串操作. 1. 常用方法 常用方法 描述 str.capitalize() 把字符串的首字母大写 str.center(wi ...
- Python标准库笔记(4) — collections模块
这个模块提供几个非常有用的Python容器类型 1.容器 名称 功能描述 OrderedDict 保持了key插入顺序的dict namedtuple 生成可以使用名字来访问元素内容的tuple子类 ...
- Python标准库笔记(3) — datetime模块
datetime模块提供了简单和复杂的方式用于操纵日期和时间的类.虽然支持日期和时间运算,但实现的重点是为了输出格式化和操作高效地提取属性. 1. 模块内容 内容 描述 常量 datetime.M ...
随机推荐
- CVPR 2013 关于图像/场景分类(classification)的文章paper list
CVPR 2013 关于图像/场景分类(classification)的文章paper list 八14by 小军 这个搜罗了cvpr2013有关于classification的相关文章,自己得m ...
- P2129 L国的战斗续之多路出击
题目描述 这一次,L国决定军队分成n组,分布在各地,若以L国为原点,可以看作在一个直角坐标系内.但是他们都受统一的指挥,指令部共发出m个命令.命令有移动.上下转移和左右转移(瞬移??),但是由于某些奇 ...
- [BZOJ2055]80人环游世界 有上下界最小费用最大流
2055: 80人环游世界 Time Limit: 10 Sec Memory Limit: 64 MB Description 想必大家都看过成龙大哥的<80天环游世界>,里面 ...
- 【BZOJ4242】水壶(克鲁斯卡尔重构树,BFS)
[BZOJ4242]水壶(克鲁斯卡尔重构树,BFS) 题面 BZOJ然而是权限题. Description JOI君所居住的IOI市以一年四季都十分炎热著称. IOI市是一个被分成纵H*横W块区域的长 ...
- centos下安装ngnix+php+mysql服务
一.nginx 安装 1.查看yum下nginx版本信息 [root@localhost ~]# yum list | grep nginx 2.手动添加nginx的yum仓库 [root@local ...
- 2:spring中的@resource
@Resource 其实是spring里面的注解注入. @Resource(这个注解属于J2EE的),默认安照名称进行装配,名称可以通过name属性进行指定, 如果没有指定name属性,当注解写在字段 ...
- C#线程篇---线程池如何管理线程(6完结篇)
C#线程基础在前几篇博文中都介绍了,现在最后来挖掘一下线程池的管理机制,也算为这个线程基础做个完结. 我们现在都知道了,线程池线程分为工作者线程和I/O线程,他们是怎么管理的? 对于Microsoft ...
- 1.Linux的发展历史以及 GNUGPL和open source
发展历史: 20实际60年代:那时候的计算机一般只有在军事,科研以及学术院校才能见到,不是一般人能接触的东西.开始的时候计算机的时候的输入靠卡片阅读器,即程序开发者在卡片上打洞放入卡片阅读器上输入,在 ...
- Java Learning之文档注释
文档注释的结构 文档注释主体的开头是一句话,概述类型或成员的作用,应自成一体.后面可跟其他句子或段落,用以详细说明类.接口.方法或字段. 除了这些描述性的段落以外,后也可跟其他段落,数量不限,并且每段 ...
- Python之——生产环境代码包发布管理fabirc
程序生产环境的发布是业务上线最后一个环境,要求具备源码打包.发布.切换.回滚.版本管理等功能,本实例实现了一整套流程,其中版本切换与回滚使用了Linux的软链接来实现.具体代码如下: # -*- ...