本篇文章给大家谈谈Python学习笔记--struct模板,以及python的struct模块的知识点,同时本文还将给你拓展01:Pythonstruct(module)、Golang相当于Pytho
本篇文章给大家谈谈Python 学习笔记 --struct 模板,以及python的struct模块的知识点,同时本文还将给你拓展01: Python struct(module)、Golang相当于Python的struct.pack / struct.unpack、matlab 学习笔记 12_4rmfield,arrayfun,structfun,struct2cell,cell2struct、python 3.3 dict:如何将struct PyDictKeysObject转换为python类?等相关知识,希望对各位有所帮助,不要忘了收藏本站喔。
本文目录一览:- Python 学习笔记 --struct 模板(python的struct模块)
- 01: Python struct(module)
- Golang相当于Python的struct.pack / struct.unpack
- matlab 学习笔记 12_4rmfield,arrayfun,structfun,struct2cell,cell2struct
- python 3.3 dict:如何将struct PyDictKeysObject转换为python类?
Python 学习笔记 --struct 模板(python的struct模块)
about
这篇文章是 Python2 的官方文档 7.3. struct
— Interpret strings as packed binary data 的一个学习笔记
官方文档简介:
This module performs conversions between Python values and C structs represented as Python strings. This can be used in handling binary data stored in files or from network connections, among other sources.
简单说来,就是 Python 中的 value (i.e. int, float, string) 和 string(似二进制般的)之间的一个转换
struct 模板主要函数有:
- pack(v1, v2, ...)
- unpack(string)
- pack_into(buffer, offset, v1, v2, ...)
- unpack_from(buffer, offset=0)
下文一一介绍
pack() and unpack()
pack()
先来看看官方说明:
- pack(fmt, v1, v2, ...):
Return a string containing the values v1, v2, ... packed according to the given format. The arguments must match the values required by the format exactly.
就是把 values:v1, v2 按照对应 fmt (format) 方式转换为 string.
- 来看个栗子:
>>> import struct
>>>
>>> v1 = 1
>>> v2 = ''abc''
>>> bytes = struct.pack(''i3s'', v1, v2)
>>> bytes
''\x01\x00\x00\x00abc''
这里的 fmt 就是''i3s''
,什么意思呢?其中 i
就是 integer, 即整数,后面的 s
对应 string。在上面的栗子中,abc
是长度为3的字符串,所以就有了 3s
.
- 这里有一个完整的 fmt 列表:
fmt.png
unpack()
同样,先看看官方文档
- unpack(fmt, string)
Unpack the string (presumably packed by pack(fmt, ...)) according to the given format. The result is a tuple even if it contains exactly one item. The string must contain exactly the amount of data required by the format (len(string) must equal calcsize(fmt)).
简单说来,就是把 string 按照对应的 fmt 形式解析出来。注意,结果返回的是一个 tuple
- 举个栗子
>>> bytes = ''\x01\x00\x00\x00abc''
>>> v1, v2 = struct.unpack(''i3s'', bytes)
>>> v1
1
>>> v2
''abc''
这就把上面的 v1,v2 还原回去了。
注意,当返回值只有一个时:
>>> a = 2
>>> a_pack = struct.pack(''i'',a)
>>> a_unpack = struct.unpack(''i'',a_pack) #此处得到的a_unpack为tuple
>>> a_unpack
(2,)
>>> a_unpack, = struct.unpack(''i'',a_pack) #此处得到的a_unpack为int
>>> a_unpack
2
Byte Order, Size, and Alignment
这里穿插一下字节的顺序,大小,和对齐问题
byte order
- 下面有个表
order.png
如果在 fmt 字符串前加上了 ''<'', 那么字节将会采用 little-endian 即小端的排列方式,如果是 ''>'' 会采用 big-endian 即大端的排列方式。默认的是''@'' 方式
- 举个栗子
>>> a = 2
>>> a_pack = struct.pack(''i'',a) #这是默认的,机器不同可能会不同,我这里默认为字节按little-endian顺序排列
>>> a_pack
''\x02\x00\x00\x00''
>>>
>>> a_pack2 = struct.pack(''>i'',a) # ''>''即big-endian
>>> a_pack2
''\x00\x00\x00\x02''
>>>
>>> a_pack3 = struct.pack(''<i'',a) #''<''即little-endian
>>> a_pack3
''\x02\x00\x00\x00''
如果不按默认的小端或大端字节排列,加上 ''<'' 或 ''>'',unpack 就要留意了
>>> a = 2
>>> a_pack2 = struct.pack(''>i'',a) #big-endian
>>> a_pack2
''\x00\x00\x00\x02''
>>> a_unpack, = struct.unpack(''<i'',a_pack2) #little-endian
>>> a_unpack
33554432
>>> a_unpack2, = struct.unpack(''>i'', a_pack2) #big-endian
>>> a_unpack2
2
如上所示,如果 pack 与 unpack 操作的字节顺序不一致,把 little-endian 和 big-endian 乱搞,就会导致数据搞乱
size and alignment
其实,struct 是类似于 C 语言中的 struct 结构体方式存储数据的。故这里有一个数据的对齐方式问题。如果在内存为 32 位 (即4GB) 机器中,一般是以 4 bytes 对齐的。CPU 一次读取4字节,然后放入对应的 cache(缓存) 中。
- 看个栗子
struct A{
char c1;
int a;
char c2;
}
结构体 A 会占用多少内存大小呢?直觉上可能是 1+4+1 = 6 字节,但一般来说,其实是 12 字节!在第一个 char 变量 c1 占用了一字节后,由于是4字节对齐的,int 变量 a 不会插在 c1 后面,而是把 c1 后面隐式的补上 3 个字节,然后把 a 放在了下面的那行中,最后把 char 变量 c2 放到 a 下面。
再看看下面的
struct A{
char c1;
char c2;
int a;
}
这种情形,结构体 A 会占用多少内存呢?答案是 8 字节。原理同上,先把 char 变量 c1 放上去,和 c1 同行的还有3字节,一看下一个 char 变量 c2 才1字节,于是就把 c2 接在 c1 后面了,此时还剩 2 字节,但是已经不够 int 了,故只能填充上2字节,然后另起一行。
想想为什么要这样呢?这岂不是浪费了内存了?!从某种意义上说,确实是浪费了内存,但这却提高了 CPU 的效率!
想想这种情景模式:假设内存中某一行已经先放了一字节的 char 变量 c, 下一个是轮到 int 变量 a 了,它一共占4字节内存,先是拿出 3 字节放在了变量 c 的后面,然后再拿最后的1字节放在下面一行。
如果 CPU 想读取 a 变量该怎么办?它应该读取2次!一次读取3字节,一次读取1字节。故这速度真是拖了,慢了一倍啊!如果变量a是另起一行的话,只要读取一次就够了,直接把4字节取走。
calcsize()
有了上了的简单认识,就好理解这个函数是干什么了的
- 文档君说
struct.calcsize(fmt)
Return the size of the struct (and hence of the string) corresponding to the given format.
简单说来,就是根据 fmt 计算出 struct 占用了内存的多少字节
- 举个栗子
>>> struct.calcsize(''ci'')
8
>>> struct.calcsize(''ic'')
5
查查上面的 format 表可知,c
对应于 char, 大小为1字节;i
对应于 int, 大小为4字节。所以,出现了上面情况,至于原因,不再累赘。只是最后的 ic
输出了5,我猜,在 struct 所占用内存行中的最后一行是不用再 padding 即填充了。
上面举的栗子都是加了 padding 的,如果不填充呢?
>>> struct.calcsize(''<ci'')
5
>>> struct.calcsize(''@ci'')
8
倘若在 fmt 前加上了 ''<'',''>'',''='',''!'' 这些,则不会 padding, 即不填充。默认的或是 ''@'' 则会。
pack_into() and pack_from()
在具体讲解之前,先来看几个函数预热一下
binascii module
这个模块用于二进制和 ASCII 码之间的转换,下面介绍几个函数
- binascii.b2a_hex(data)
binascii.hexlify(data)
Return the hexadecimal representation of the binary data. Every byte of data is converted into the corresponding 2-digit hex representation. The resulting string is therefore twice as long as the length of data.
简单说来,就是用十六进制表示二进制数。
- 举个栗子
>>> import binascii
>>> s = ''abc''
>>> binascii.b2a_hex(s)
''616263''
>>> binascii.hexlify(s)
''616263''
- binascii.a2b_hex(hexstr)
binascii.unhexlify(hexstr)
Return the binary data represented by the hexadecimal string hexstr. This function is the inverse of b2a_hex()
hexstr must contain an even number of hexadecimal digits (which can be upper or lower case), otherwise a TypeError is raised.
简单说来,就是上面函数的反操作,即把十六进制串转为二进制数据
- 举个栗子
>>> binascii.a2b_hex(''616263'')
''abc''
>>> binascii.unhexlify(''616263'')
''abc''
pack_into() and pack_from()
- 文档说
struct.pack_into(fmt, buffer, offset, v1, v2, ...)
Pack the values v1, v2, ...
according to the given format, write the packed bytes into the writable buffer starting at offset. Note that the offset is a required argument.
简单说来,就是把 values:v1, v2, ... 打包按格式 fmt 转换后写入指定的内存 buffer 中,并且可以指定 buffer 中的 offset 即偏移量,从哪里开始写。
struct.unpack_from(fmt, buffer[, offset=0])
Unpack the buffer according to the given format. The result is a tuple even if it contains exactly one item. The buffer must contain at least the amount of data required by the format (len(buffer[offset:])
must be at least calcsize(fmt)).
简单说来,就是从内存中的指定 buffer 区读取出来,然后按照 fmt 格式解析。可以指定 offset,从 buffer 的哪个位置开始读取。
相比于前面的 pack, unpack,这两个函数有什么作用呢?我们也可以看出区别,就是多了 buffer 这东东,内存中的一个缓冲区。在前面,pack 需要将 values v1, v2 打包放入内存中某个区域,而这某个区域是程序内部定的,可能会让出很多的空间给它放,这有点浪费了。其次,如果每次间断性的来一些 vlaues,然后又要开辟新的空间,这效率有点慢了,拖时间啊!那还不如我们一次性给定算了,而且我们可以指定多少内存给它,这样就不会浪费内存了。
- 举个栗子
import struct
import binascii
import ctypes
vals1 = (1, ''hello'', 1.2)
vals2 = (''world'', 2)
s1 = struct.Struct(''I5sf'')
s2 = struct.Struct(''5sI'')
print ''s1 format: '', s1.format
print ''s2 format: '', s2.format
b_buffer = ctypes.create_string_buffer(s1.size+s2.size) #开出一块buffer
print ''Before pack:'',binascii.hexlify(b_buffer)
s1.pack_into(b_buffer,0,*vals1)
s2.pack_into(b_buffer,s1.size,*vals2)
print ''After pack:'',binascii.hexlify(b_buffer)
print ''vals1 is:'', s1.unpack_from(b_buffer,0)
print ''vals2 is:'', s2.unpack_from(b_buffer,s1.size)
结果输出:
s1 format: I5sf
s2 format: 5sI
Before pack: 00000000000000000000000000000000000000000000000000000000
After pack: 0100000068656c6c6f0000009a99993f776f726c6400000002000000
vals1 is: (1, ''hello'', 1.2000000476837158)
vals2 is: (''world'', 2)
咋看之下,我们用了 class struct.Struct(format) 这个类,这跟前面是有一点不同,前面我们是面向过程,但现在是面向对象了,但各函数功能还是一样的。
这里需要注意的一点是,float 在 unpack 后的精度变了!
这里,由于 vals1, vals2 是 tuple, 故在函数传递时用
*vals1
带上星号 *, 会把带星号 * 的 tuple,此处的 vals1, vals2 解析出单独的数据。没有星号 * 就会出现参数错误。
01: Python struct(module)
Python struct
struct 是Python 的一个内置模块
作用: 将 Python 中数字(可以是其它类型)进行压缩(bytes)
应用: 传输数据时,将文件的报头(信息)传输到客户端,应该先告诉数据的大小,如果数据十分大,所占的大小是不固定的,这时就要用到struct
将所占的大小压缩成固定的大小
理解: 将52345234
压缩成四个字节
基本使用
压缩
import struct # 导入struct模块
num = 5234532 # 定义一个无序长度的数字
num_bytes = struct.pack(''L'', num) # 将数字进行打包,返回bytes类型,参数(''i''=> 代表的是将int类型进行压缩, num=>要压缩的数字)
其它类型进行压缩:
解压
size = struct.unpack(''L'', num)
# 返回元组,可以用size[0]进行获取解压的数据
# 参数(''i''=>用啥压缩就用啥解压, num=>压缩后的字符流)
Golang相当于Python的struct.pack / struct.unpack
import struct print struct.pack(''L'',64) "@\x00\x00\x00\x00\x00\x00\x00" struct.unpack(''L'',''@\x00\x00\x00\x00\x00\x00\x00'') (64,)
我想在Go做类似的事情,除非我对如何做到这一点有点不清楚.我知道我可以这样做:
import ( "encoding/binary" "fmt" ) bs := make([]byte,8) binary.PutUvarint(bs,uint64(64)) fmt.Printf("%s",bs) "@"
但那是非常不同的,可能不是我想要的.
解决方法
https://play.golang.org/p/e81LuPO_JR
bs := make([]byte,8) binary.LittleEndian.PutUint64(bs,uint64(64)) fmt.Printf("%#v\n",bs) i := binary.LittleEndian.Uint64(bs) fmt.Println(i)
matlab 学习笔记 12_4rmfield,arrayfun,structfun,struct2cell,cell2struct
一起来学 matlab-matlab 学习笔记 12
12_4 结构体
rmfield,arrayfun,structfun,struct2cell,cell2struct
觉得有用的话,欢迎一起讨论相互学习~Follow Me
参考文献 https://ww2.mathworks.cn/help/matlab/ref/rmfield.html https://ww2.mathworks.cn/help/matlab/ref/arrayfun.html https://ww2.mathworks.cn/help/matlab/ref/structfun.html https://ww2.mathworks.cn/help/matlab/ref/struct2cell.html https://ww2.mathworks.cn/help/matlab/ref/cell2struct.html
<font color=Red>refield</font>
- 删除结构体中的字段
- s = rmfield(s,field)
- s = rmfield (s,field) 从结构体数组 s 中删除指定的一个或多个字段。使用字符向量元胞数组或字符串数组指定多个字段。s 的维度保持不变。
定义一个包含 first、second、third 和 fourth 字段的标量结构体。
S.first = 1;
S.second = 2;
S.third = 3;
S.fourth = 4;
删除字段 first 和 fourth。
fields = {''first'',''fourth''};
S = rmfield(S,fields)
S = struct with fields:
second: 2
third: 3
<font color=Red>arrayfun</font>
- 将函数应用于每个数组元素,区别在于 structfun 的输入参数必须是标量结构体。
<font color=Orange> 语法 </font>
- B = arrayfun(func,A)
- B = arrayfun (func,A) 将函数 func 应用于 A 的元素,一次一个元素。然后 arrayfun 将 func 的输出串联成输出数组 B,因此,对于 A 的第 i 个元素来说,B (i) = func (A (i))。输入参数 func 是一个函数的函数句柄,此函数接受一个输入参数并返回一个标量。func 的输出可以是任何数据类型,只要该类型的对象可以串联即可。数组 A 和 B 必须具有相同的大小。 您不能指定 arrayfun 计算 B 的各元素的顺序,也不能指望它们按任何特定的顺序完成计算。
创建一个非标量结构体数组。每个结构体有一个包含随机数向量的字段。这些向量具有不同的大小。
S(1).f1 = rand(1,5);
S(2).f1 = rand(1,10);
S(3).f1 = rand(1,15)
S = 1x3 struct array with fields:
f1
使用 arrayfun 函数计算 S 中每个字段的均值。不能使用 structfun 完成此计算,因为 structfun 的输入参数必须是标量结构体。
A = arrayfun(@(x) mean(x.f1),S)
A = 1×3
0.6786 0.6216 0.6069
- B = arrayfun(func,A1,...,An)
- B = arrayfun (func,A1,...,An) 将 func 应用于数组 A1,...,An 的元素,因此 B (i) = func (A1 (i),...,An (i))。函数 func 必须接受 n 个输入参数并返回一个标量。数组 A1,...,An 的大小必须全部相同。
创建一个结构体数组,其中每个结构体有两个包含数值数组的字段。
S(1).X = 5:5:100; S(1).Y = rand(1,20);
S(2).X = 10:10:100; S(2).Y = rand(1,10);
S(3).X = 20:20:100; S(3).Y = rand(1,5)
S = 1x3 struct array with fields:
X
Y
绘制数值数组。从 plot 函数返回一个图形线条对象的数组,并使用这些对象为每一组数据点添加不同的标记。arrayfun 可以返回任何数据类型的数组,只要该数据类型的对象可以串联即可。
figure
hold on
p = arrayfun(@(a) plot(a.X,a.Y),S);
p(1).Marker = ''o'';
p(2).Marker = ''+'';
p(3).Marker = ''s'';
hold off
- B = arrayfun( ___ ,Name,Value)
- B = arrayfun (___ ,Name,Value) 应用 func 并使用一个或多个 Name,Value 对组参数指定其他选项。例如, 要以元胞数组形式返回输出值,请指定 ''UniformOutput'',false。 当 func 返回的值不能串联成数组时,可以按元胞数组的形式返回 B。可以将 Name,Value 对组参数与上述任何语法中的输入参数结合使用。
创建一个非标量结构体数组。每个结构体有一个包含数值矩阵的字段。
S(1).f1 = rand(3,5); S(2).f1 = rand(6,10); S(3).f1 = rand(4,2) S = 1x3 struct array with fields: f1
使用 arrayfun 函数计算 S 中每个字段的均值。mean 返回包含每列均值的向量,因此不能以数组的形式返回均值。要以元胞数组的形式返回均值,请指定 ''UniformOutput'',false 名称 - 值对组。
A = arrayfun(@(x) mean(x.f1),S,''UniformOutput'',false) A = 1x3 cell array {1x5 double} {1x10 double} {1x2 double}
* [B1,...,Bm] = arrayfun( ___ )
* 当 func 返回 m 个输出值时,[B1,...,Bm] = arrayfun( ___ ) 返回多个输出数组 B1,...,Bm。func 可以返回不同数据类型的输出参数,但每一次调用 func 时返回的每个输出的数据类型必须相同。可以将此语法与前面语法中的任何输入参数结合使用。
* 从 func 返回的输出参数的数量可以不同于 A1,...,An 指定的输入参数的数量。
创建一个非标量结构体数组。
S(1).f1 = 1:10; S(2).f1 = [2; 4; 6]; S(3).f1 = [] S = 1x3 struct array with fields: f1
使用 arrayfun 函数计算 S 中每个字段的大小。行数和列数分别输出在两个 1×3 数值数组中。
[nrows,ncols] = arrayfun(@(x) size(x.f1),S) nrows = 1×3
1 3 0
ncols = 1×3
10 1 0
---
# <font color=Red>structfun</font>
* 对标量结构体的每个字段应用函数--**和arrayfun不同,arrayfun对所有元素应用函数,structfun对所有字段应用函数**
* A = structfun(func,S)
* A = structfun(func,S) 将函数 func 应用于标量结构体 S 的每个字段,每次一个字段。然后 structfun 将 func 的输出串联成列向量 A。输入参数 func 是一个函数的函数句柄,此函数接受一个输入参数并返回一个标量。func 的输出可以是任何数据类型,只要该类型的对象可以串联即可。A 中的元素数等于 S 中的字段数。
创建一个标量结构体,其字段中包含不同大小的数值数组。
S.f1 = 1:10; S.f2 = [2; 4; 6]; S.f3 = [] S = struct with fields: f1: [1 2 3 4 5 6 7 8 9 10] f2: [3x1 double] f3: []
计算每个数值数组的均值,然后以数组的形式返回这些均值。
A = structfun(@mean,S) A = 3×1
5.5000 4.0000 NaN
* A = structfun(func,S,Name,Value)
* A = structfun(func,S,Name,Value) 应用 func 并使用一个或多个 Name,Value 对组参数指定其他选项。例如,要以结构体形式返回输出值,**请指定 ''UniformOutput'',false。** 当 func 返回的值不能合并为数组时,可以按结构体形式返回 A。返回的结构体具有与 S 相同的字段。
创建一个标量结构体,其字段中包含矩阵。
S.f1 = 1:10; S.f2 = [2 3; 4 5; 6 7]; S.f3 = rand(4,4) S = struct with fields: f1: [1 2 3 4 5 6 7 8 9 10] f2: [3x2 double] f3: [4x4 double]
计算每个矩阵的均值。mean 返回包含每列均值的向量,因此不能以数组的形式返回均值。要以结构体形式返回均值,请指定 ''UniformOutput'',false 名称 - 值对组。
A = structfun(@mean,S,''UniformOutput'',false) A = struct with fields: f1: 5.5000 f2: [4 5] f3: [0.6902 0.3888 0.7627 0.5962]
* [A1,...,Am] = structfun( ___ )
* 当 func 返回 m 个输出值时,[A1,...,Am] = structfun(_ __ ) 返回多个输出数组 A1,...,Am。func 可以返回不同数据类型的输出参数,但每次调用 func 时返回的每个输出的数据类型必须相同。可以将此语法与前面语法中的任何输入参数结合使用。
创建一个标量结构体。
S.f1 = 1:10; S.f2 = [2 3; 4 5; 6 7]; S.f3 = rand(4,4) S = struct with fields: f1: [1 2 3 4 5 6 7 8 9 10] f2: [3x2 double] f3: [4x4 double]
计算 S 中每个数组的大小。行数和列数都是一个 3×1 数值数组。
[nrows,ncols] = structfun(@size,S) nrows = 3×1
1
3
4
ncols = 3×1
10
2
4
---
# <font color=Red>struct2cell</font>
* 将结构体转换为元胞数组
* C = struct2cell(S)
* C = struct2cell(S) 将结构体转换为元胞数组。元胞数组 C 包含从 S 的字段复制的值。
* struct2cell 函数不返回字段名称。要返回元胞数组中的字段名称,请使用 fieldnames 函数。
```matlab
创建一个结构体。
S.x = linspace(0,2*pi);
S.y = sin(S.x);
S.title = ''y = sin(x)''
S = struct with fields:
x: [1x100 double]
y: [1x100 double]
title: ''y = sin(x)''
将 S 转换为元胞数组。
C = struct2cell(S)
C = 3x1 cell array
{1x100 double}
{1x100 double}
{''y = sin(x)''}
元胞数组不包含字段名称。要返回元胞数组中的字段名称,请使用 fieldnames 函数。fieldnames 和 struct2cell 以相同的顺序返回字段名称和值。
fields = fieldnames(S)
fields = 3x1 cell array
{''x'' }
{''y'' }
{''title''}
<font color=Red>cell2struct</font>
- 将元胞数组转换为结构体数组
- structArray = cell2struct(cellArray, fields, dim)
- structArray = cell2struct (cellArray, fields, dim) 通过元胞数组 cellArray 中包含的信息创建一个结构体数组 structArray。
- fields 参数指定结构体数组的字段名称。此参数是一个字符数组、字符向量元胞数组或字符串数组。
- dim 参数向 MATLAB® 指示创建结构体数组时要使用的元胞数组的轴。使用数值 double 指定 dim。
- 要使用从元胞数组的 N 行中获取的字段创建一个结构体数组,请在 fields 参数中指定 N 个字段名称,在 dim 参数中指定数字 1。要使用从元胞数组的 M 列中获取的字段创建一个结构体数组,请在 fields 参数中指定 M 个字段名称,在 dim 参数中指定数字 2。
- structArray 输出是具有 N 个字段的结构体数组,其中 N 等于 fields 输入参数中的字段数。生成的结构体中的字段数必须等于沿要转换的维度 dim 的元胞数。
<font color=Orange> 示例 </font>
- 创建下表以用于此部分中的示例。表中列出了有关一个小型工程公司的员工的信息。按行读取该表将显示按部门列出的员工姓名。按列读取该表将显示每个员工已在该公司工作的年数。
输入以下命令以创建初始元胞数组 employees:
devel = {{''Lee'',''Reed'',''Hill''}, {''Dean'',''Frye''}, ...
{''Lane'',''Fox'',''King''}};
sales = {{''Howe'',''Burns''}, {''Kirby'',''Ford''}, {''Hall''}};
mgmt = {{''Price''}, {''Clark'',''Shea''}, {''Sims''}};
qual = {{''Bates'',''Gray''}, {''Nash''}, {''Kay'',''Chase''}};
docu = {{''Lloyd'',''Young''}, {''Ryan'',''Hart'',''Roy''}, {''Marsh''}};
employees = [devel; sales; mgmt; qual; docu]
employees =
{1x3 cell} {1x2 cell} {1x3 cell}
{1x2 cell} {1x2 cell} {1x1 cell}
{1x1 cell} {1x2 cell} {1x1 cell}
{1x2 cell} {1x1 cell} {1x2 cell}
{1x2 cell} {1x3 cell} {1x1 cell}
将元胞数组转换为沿维度 1 的结构体
- 转换沿其第一个维度的 5×3 元胞数组以构造一个具有 5 个字段的 3×1 结构体。沿元胞数组的维度 1 的每一行将变为结构体数组中的一个字段: 遍历第一个维度(即垂直维度),包含 5 行,每行的标题如下:
rowHeadings = {''development'', ''sales'', ''management'', ''quality'', ''documentation''}; 2. 将元胞数组转换为与此维度相关的结构体数组 depts:
depts = cell2struct(employees, rowHeadings, 1)
depts =
3x1 struct array with fields:
development
sales
management
quality
documentation
- 使用此面向行的结构体查找已在公司工作超过 10 年的开发员工的姓名:
depts(1:2).development
ans =
''Lee'' ''Reed'' ''Hill''
ans =
''Dean'' ''Frye''
将相同的元胞数组转换为沿维度 2 的结构体
- 转换沿其第二个维度的 5×3 元胞数组以构造一个具有 3 个字段的 5×1 结构体。沿元胞数组的维度 2 的每一列将变为结构体数组中的一个字段:
- 沿第二个维度(或水平维度)遍历元胞数组。列标题将变为生成的结构体的字段:
colHeadings = {''fiveYears'' ''tenYears'' ''fifteenYears''};
years = cell2struct(employees, colHeadings, 2)
years =
5x1 struct array with fields:
fiveYears
tenYears
fifteenYears
- 使用列向结构体时,将显示已在公司工作至少 5 年的销售和文件部门的员工数。
[~, sales_5years, ~, ~, docu_5years] = years.fiveYears
sales_5years =
''Howe'' ''Burns''
docu_5years =
''Lloyd'' ''Young''
仅将元胞数组的一部分转换为结构体:
- 仅转换元胞数组的第一行和最后一行。这将生成一个具有 2 个字段的 3×1 结构体数组:
rowHeadings = {''development'', ''documentation''};
depts = cell2struct(employees([1,5],:), rowHeadings, 1)
depts =
3x1 struct array with fields:
development
documentation
2. 显示对于所有三个时间段属于这些部门的员工:
for k=1:3
depts(k,:)
end
ans =
development: {''Lee'' ''Reed'' ''Hill''}
documentation: {''Lloyd'' ''Young''}
ans =
development: {''Dean'' ''Frye''}
documentation: {''Ryan'' ''Hart'' ''Roy''}
ans =
development: {''Lane'' ''Fox'' ''King''}
documentation: {''Marsh''}
python 3.3 dict:如何将struct PyDictKeysObject转换为python类?
我相信我已成功翻译了这个结构.
typedef PyDictKeyEntry *(*dict_lookup_func) (PyDictObject *mp,PyObject *key,Py_hash_t hash,PyObject ***value_addr); struct _dictkeysobject { Py_ssize_t dk_refcnt; Py_ssize_t dk_size; dict_lookup_func dk_lookup; Py_ssize_t dk_usable; PyDictKeyEntry dk_entries[1]; };
我认为以下看起来很好:
from ctypes import Structure,c_ulong,POINTER,cast,py_object,CFUNCTYPE LOOKUPFUNC = CFUNCTYPE(POINTER(PyDictKeyEntry),POINTER(PyDictObject),POINTER(POINTER(py_object))) class PyDictKeysObject(Structure): """A key object""" _fields_ = [ ('dk_refcnt',c_ssize_t),('dk_size',('dk_lookup',LOOKUPFUNC),('dk_usable',('dk_entries',PyDictKeyEntry * 1),] PyDictKeysObject._dk_entries = PyDictKeysObject.dk_entries PyDictKeysObject.dk_entries = property(lambda s: cast(s._dk_entries,POINTER(PyDictKeyEntry * s.dk_size))[0])
这行代码现在有效,其中d == {0:0,1:1,2:2,3:3}:
obj = cast(id(d),POINTER(PyDictObject)).contents # works!!`
这是我在C struct PyDictObject中的翻译:
class PyDictObject(Structure): # an incomplete type """A dictionary object.""" def __len__(self): """Return the number of dictionary entry slots.""" pass def slot_of(self,key): """Find and return the slot at which `key` is stored.""" pass def slot_map(self): """Return a mapping of keys to their integer slot numbers.""" pass PyDictObject._fields_ = [ ('ob_refcnt',('ob_type',c_void_p),('ma_used',('ma_keys',POINTER(PyDictKeysObject)),('ma_values',POINTER(py_object)),# points to array of ptrs ]
解决方法
class PyDictKeyEntry(Structure): """An entry in a dictionary.""" _fields_ = [ ('me_hash',c_ulong),('me_key',py_object),('me_value',] class PyDictObject(Structure): """A dictionary object.""" pass LOOKUPFUNC = CFUNCTYPE(POINTER(PyDictKeyEntry),POINTER(POINTER(py_object))) class PyDictKeysObject(Structure): """An object of key entries.""" _fields_ = [ ('dk_refcnt',# a function prototype per docs ('dk_usable',# an array of size 1; size grows as keys are inserted into dictionary; this variable-sized field was the trickiest part to translate into python ] PyDictObject._fields_ = [ ('ob_refcnt',# Py_ssize_t translates to c_ssize_t per ctypes docs ('ob_type',# Could not find this in the docs ('ma_used',# Py_Object* translates to py_object per ctypes docs ] PyDictKeysObject._dk_entries = PyDictKeysObject.dk_entries PyDictKeysObject.dk_entries = property(lambda s: cast(s._dk_entries,POINTER(PyDictKeyEntry * s.dk_size))[0]) # this line is called every time the attribute dk_entries is accessed by a PyDictKeyEntry instance; it returns an array of size dk_size starting at address _dk_entries. (POINTER creates a pointer to the entire array; the pointer is dereferenced (using [0]) to return the entire array); the code then accesses the ith element of the array)
以下函数提供对python字典底层的PyDictObject的访问:
def dictobject(d): """Return the PyDictObject lying behind the Python dict `d`.""" if not isinstance(d,dict): raise TypeError('cannot create a dictobject from %r' % (d,)) return cast(id(d),POINTER(PyDictObject)).contents
如果d是具有键值对的python字典,则obj是包含键值对的PyDictObject实例:
obj = cast(id(d),POINTER(PyDictObject)).contents
PyDictKeysObject的一个实例是:
key_obj = obj.ma_keys.contents
指向存储在字典的插槽0中的密钥的指针是:
key_obj.dk_entries[0].me_key
使用这些类的程序以及探测插入到字典中的每个键的哈希冲突的例程位于here.我的代码是由Brandon Rhodes为python 2.x编写的代码的修改.他的代码是here.
关于Python 学习笔记 --struct 模板和python的struct模块的介绍已经告一段落,感谢您的耐心阅读,如果想了解更多关于01: Python struct(module)、Golang相当于Python的struct.pack / struct.unpack、matlab 学习笔记 12_4rmfield,arrayfun,structfun,struct2cell,cell2struct、python 3.3 dict:如何将struct PyDictKeysObject转换为python类?的相关信息,请在本站寻找。
本文标签: