动态构建python Construct解析数据

Python Construct提供了一种快速解析格式化数据流的方式。Python Construct可以用来解析文件,网络数据包等带有格式的数据流。为了解析一种格式的数据流,我们只需要用Construct的语法描述这种数据流格式即可。

举个例子,为了解析一个3个char类型的变量,可以定义如下的Construct。

foo = Struct(“foo”,
 		UBInt8(“a”),
 		UBInt8(“b”),
 		UBInt8(“c”),)
obj = foo.parse(“\x00\x01\x02")

上面的Construct是写死的,只能用来解析一种数据格式。如何在运行时动态的生成能够解析各种数据格式的Construct对象呢?为了回答这个问题,我们首先需要研究一下Struct的构造函数。

Struct的构造函数接收了一个元组作为参数,那么我们就需要动态的构造一个元组。然而在python中,元组的成员一旦生成是不可变的,因此不可能直接动态的生成一个元组。

我们可以利用列表构建元组。在python中,列表的元素是动态可变的,同时可以使用tuple将列表转换成一个元组。对于上面的例子我们就可以这样动态的构造元组:

subcons = []
subcons.append(UBInt8(“a"))
subcons.append(UBInt8(“b"))
subcons.append(UBInt8(“c"))
args = tuple(subcons)

这还没完! 我们不可能直接讲这个args传递给Struct的构造函数,Struct(“foo”, args),这样args会被认为是一个数据对象,而且类型为元组,在执行构造函数时会报异常。

在python中我们可以使用*操作符讲一个数据对象转换为原始形式。例如*args就表示

UBInt8(“a”), UBInt8(“b”), UBInt8(“c")

这样的话我们就得到了和Struct构造函数完全一样的参数。

动态构建Construct的完整代码如下:

subcons = []
subcons.append(UBInt8(“a"))
subcons.append(UBInt8(“b"))
subcons.append(UBInt8(“c"))
args = tuple(subcons)
foo = Struct(“foo”, *args)
foo.parse(“\x00\x01\x02")