gpt4 book ai didi

python - 扩展 ctypes 以指定字段重载

转载 作者:行者123 更新时间:2023-12-01 02:42:30 25 4
gpt4 key购买 nike

我想扩展 ctypes Structure、BigEndianStructure、LittleEndianStructure。

能够指定每个字段进行描述,并重载变量返回到可能的枚举、polyco 等属性的方式。

我想做的事情如下所示,但不确定如何创建 ModifedCTypesStructure 父类。

我的目标是使用它来命令/遥测二进制数据。

class Color(Enum): 
RED = 1
GREEN = 2
BLUE = 3

class Packet(ModifedCTypesStructure):
__fields__ = [("fieldA",ctypes.c_int32,
{"brief":"""Description of fieldA""",
"enum":Color}
),
("fieldB",ctypes.c_uint32,
{"repr":lambda x: hex(x)}
)
]

a = Packet()
help(a.fieldA)
> Description of fieldA
a.fieldA = Color.RED
print a._fieldA # Return the binary field
> 1
a.fieldB = 0xbb
print a.fieldB
> 0xbb #Note repr is called to return '0xbb'
print a._fieldB
> 187

最佳答案

有可能 -ctypes.Structure 提供的大部分魔力是由于它的字段是“描述符”——即 Python's descriptor protocol 之后的对象。 - 类似于我们在类主体中使用 @property 装饰器时得到的结果。

ctypes.Structure 有一个元类,负责将特殊大小写变量名 _fields_ 中列出的每个字段转换为 _ctypes.CField对象(您可以通过在交互式 Python 提示符中验证 type(mystryct.field) 的结果来检查这一点。

因此,为了扩展字段本身的行为,我们需要扩展此 CField 类 - 并修改创建 Strutcture 的元类以使用我们的字段。 CField 类本身似乎是一个普通的 Python 类 - 因此,如果我们尊重对 super 方法的调用,则很容易修改。

但是您的“愿望 list ”中有一些问题:

  1. 使用“help”需要 Python 对象将帮助字符串嵌入到其类 __doc__ 属性(而不是实例)中。因此,每次从结构类中检索字段本身时,我们都可以动态地创建一个具有所需帮助的新类。

  2. 当从对象中检索值时,Python 无法提前“知道”该值是仅用于 repr“查看”还是实际使用。因此,我们要么为具有自定义表示的值自定义 a.fieldB 返回的值,要么根本不这样做。下面的代码确实在字段检索上创建一个动态类,该类将具有自定义表示形式,并尝试保留基础值的所有其他数字属性。但这设置起来既慢又可能会出现一些不兼容性 - 您可以选择在不调试值时关闭它,或者只是获取原始值。

  3. Ctype 的“字段”当然会有一些自己的内部结构,例如每个内存位置的偏移量等等 - 因此,我建议采用以下方法:(1)创建一个新的“字段” “根本不继承自 ctypes.Field 的类 - 并且实现您想要的增强功能; (2) 在创建 ModifiedStructure 时,创建所有带“_”前缀的名称,并将这些名称传递给原始 Ctypes.Structure 元类,以像往常一样创建其字段; (3) 让我们的“Field”类读取和写入原始的ctypes.Fields,并拥有它们的自定义转换和表示。

如您所见,我还负责在写入时实际转换 Enum 值。

要尝试一切,只需继承下面的“ModifiedStructure”,而不是ctypes.Structure:

from ctypes import Structure
import ctypes


class A(Structure):
_fields_ = [("a", ctypes.c_uint8)]

FieldType = type(A.a)
StructureType = type(A)

del A


def repr_wrapper(value, transform):
class ReprWrapper(type(value)):
def __new__(cls, value):
return super().__new__(cls, value)
def __repr__(self):
return transform(self)

return ReprWrapper(value)


def help_wrapper(field):
class Field2(field.__class__):
__doc__ = field.help

def __repr__(self):
return self.__doc__

return Field2(field.name, field.type_, help=field.help, repr=field.repr, enum=field.enum)


class Field:
def __init__(self, name, type_, **kwargs):
self.name = name
self.type_ = type_
self.real_name = "_" + name
self.help = kwargs.pop("brief", f"Proxy structure field {name}")
self.repr = kwargs.pop("repr", None)
self.enum = kwargs.pop("enum", None)
if self.enum:
self.rev_enum = {constant.value:constant for constant in self.enum.__members__.values() }

def __get__(self, instance, owner):
if not instance:
return help_wrapper(self)

value = getattr(instance, self.real_name)
if self.enum:
return self.rev_enum[value]
if self.repr:
return repr_wrapper(value, self.repr)

return value

def __set__(self, instance, value):
if self.enum:
value = getattr(self.enum, value.name).value
setattr(instance, self.real_name, value)


class ModifiedStructureMeta(StructureType):
def __new__(metacls, name, bases, namespace):
_fields = namespace.get("_fields_", "")
classic_fields = []
for field in _fields:
# Create the set of descriptors for the new-style fields:
name = field[0]
namespace[name] = Field(name, field[1], **(field[2] if len(field) > 2 else {}))
classic_fields.append(("_" + name, field[1]))

namespace["_fields_"] = classic_fields
return super().__new__(metacls, name, bases, namespace)


class ModifiedStructure(ctypes.Structure, metaclass=ModifiedStructureMeta):
__slots__ = ()

并在交互式提示上测试它:

In [165]: class A(ModifiedStructure):
...: _fields_ = [("b", ctypes.c_uint8, {"enum": Color, 'brief': "a color", }), ("c", ctypes.c_uint8, {"repr": hex})]
...:
...:

In [166]: a = A()

In [167]: a.c = 20

In [169]: a.c
Out[169]: 0x14

In [170]: a.c = 256

In [171]: a.c
Out[171]: 0x0

In [172]: a.c = 255

In [173]: a.c
Out[173]: 0xff

In [177]: a.b = Color.RED

In [178]: a._b
Out[178]: 1

In [180]: help(A.b)
(shows full Field class help starting with the given description)

In [181]: A.b
Out[181]: a color

关于python - 扩展 ctypes 以指定字段重载,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45527945/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com