Python ctypes:具有位字段初始化的结构
Python ctypes: structure with bit fields initialization
我注意到当 ctypes.Structure 派生 class 的对象中有位字段时,我无法默认初始化它,但我可以默认初始化此类对象的数组。
假设我们定义这样一个 class:
class What(ctypes.Structure):
_fields_ = [('x', ctypes.c_float), ('y', ctypes.c_short, 2)]
def __init__(self, x=None, y=None):
if not x:
x = ctypes.c_float()
if not y:
y = ctypes.c_short()
super(What, self).__init__(x, y)
现在这段代码执行顺利,据我所知,它使用了上面定义的默认构造函数。
what_arr = What * 4
w_arr = what_arr()
返回一个由零填充结构组成的数组。但是,当我尝试只初始化一个对象时,出现 'access violation reading location' 错误并且程序崩溃。
w = What()
如果有人解释幕后发生的事情以及这种行为的原因是什么,那就太好了。
更多详细信息:
我需要
x = ctypes.c_float()
y = ctypes.c_short()
而不是直接将 0 传递给初始化,因为通常结构的字段包含其他结构,我也想在这里使用它们的默认构造函数(以便所有内容都用 0 递归初始化)。
我相信这对于想要先用虚拟值测试一些包装包的人可能有用。
基础class不知道x
和y
是什么。如果我正确理解了 OP,那么 ctypes.Structure
的默认行为就是所需要的。我添加了一个 __repr__
函数以更轻松地查看发生了什么:
class What(ctypes.Structure):
_fields_ = [('x', ctypes.c_float), ('y', ctypes.c_short, 2)]
def __repr__(self):
return f'What(x={self.x},y={self.y})'
正在测试...
>>> w = What()
>>> w
What(x=0.0,y=0)
>>> w = What(1.5)
>>> w
What(x=1.5,y=0)
>>> w = What(1.5,2)
>>> w
What(x=1.5,y=-2)
>>> wa = (What*4)()
>>> list(wa)
[What(x=0.0,y=0), What(x=0.0,y=0), What(x=0.0,y=0), What(x=0.0,y=0)]
另请注意,默认情况下 ctypes 结构是零初始化的,因此即使对于嵌套结构,您也不需要任何魔法:
import ctypes
class Inner(ctypes.Structure):
_fields_ = [('a',ctypes.c_int),('b',ctypes.c_int)]
def __repr__(self):
return f'Inner(a={self.a},b={self.b})'
class What(ctypes.Structure):
_fields_ = [('x', Inner), ('y', ctypes.c_short, 2)]
def __repr__(self):
return f'What(x={self.x},y={self.y})'
正在测试...
>>> w = What()
>>> w
What(x=Inner(a=0,b=0),y=0)
>>> wa = (What*4)()
>>> list(wa)
[What(x=Inner(a=0,b=0),y=0), What(x=Inner(a=0,b=0),y=0), What(x=Inner(a=0,b=0),y=0), What(x=Inner(a=0,b=0),y=0)]
我注意到当 ctypes.Structure 派生 class 的对象中有位字段时,我无法默认初始化它,但我可以默认初始化此类对象的数组。
假设我们定义这样一个 class:
class What(ctypes.Structure):
_fields_ = [('x', ctypes.c_float), ('y', ctypes.c_short, 2)]
def __init__(self, x=None, y=None):
if not x:
x = ctypes.c_float()
if not y:
y = ctypes.c_short()
super(What, self).__init__(x, y)
现在这段代码执行顺利,据我所知,它使用了上面定义的默认构造函数。
what_arr = What * 4
w_arr = what_arr()
返回一个由零填充结构组成的数组。但是,当我尝试只初始化一个对象时,出现 'access violation reading location' 错误并且程序崩溃。
w = What()
如果有人解释幕后发生的事情以及这种行为的原因是什么,那就太好了。
更多详细信息:
我需要
x = ctypes.c_float()
y = ctypes.c_short()
而不是直接将 0 传递给初始化,因为通常结构的字段包含其他结构,我也想在这里使用它们的默认构造函数(以便所有内容都用 0 递归初始化)。
我相信这对于想要先用虚拟值测试一些包装包的人可能有用。
基础class不知道x
和y
是什么。如果我正确理解了 OP,那么 ctypes.Structure
的默认行为就是所需要的。我添加了一个 __repr__
函数以更轻松地查看发生了什么:
class What(ctypes.Structure):
_fields_ = [('x', ctypes.c_float), ('y', ctypes.c_short, 2)]
def __repr__(self):
return f'What(x={self.x},y={self.y})'
正在测试...
>>> w = What()
>>> w
What(x=0.0,y=0)
>>> w = What(1.5)
>>> w
What(x=1.5,y=0)
>>> w = What(1.5,2)
>>> w
What(x=1.5,y=-2)
>>> wa = (What*4)()
>>> list(wa)
[What(x=0.0,y=0), What(x=0.0,y=0), What(x=0.0,y=0), What(x=0.0,y=0)]
另请注意,默认情况下 ctypes 结构是零初始化的,因此即使对于嵌套结构,您也不需要任何魔法:
import ctypes
class Inner(ctypes.Structure):
_fields_ = [('a',ctypes.c_int),('b',ctypes.c_int)]
def __repr__(self):
return f'Inner(a={self.a},b={self.b})'
class What(ctypes.Structure):
_fields_ = [('x', Inner), ('y', ctypes.c_short, 2)]
def __repr__(self):
return f'What(x={self.x},y={self.y})'
正在测试...
>>> w = What()
>>> w
What(x=Inner(a=0,b=0),y=0)
>>> wa = (What*4)()
>>> list(wa)
[What(x=Inner(a=0,b=0),y=0), What(x=Inner(a=0,b=0),y=0), What(x=Inner(a=0,b=0),y=0), What(x=Inner(a=0,b=0),y=0)]