是否有一种方法可以方便地在Python中定义类c结构?我厌倦了写这样的东西:
class MyStruct():
def __init__(self, field1, field2, field3):
self.field1 = field1
self.field2 = field2
self.field3 = field3
是否有一种方法可以方便地在Python中定义类c结构?我厌倦了写这样的东西:
class MyStruct():
def __init__(self, field1, field2, field3):
self.field1 = field1
self.field2 = field2
self.field3 = field3
当前回答
我能想到的最干净的方法是使用一个类装饰器,它可以让你声明一个静态类,并将其重写为一个具有正常命名属性的结构体:
from as_struct import struct
@struct
class Product():
name = 'unknown product'
quantity = -1
sku = '-'
# create instance
p = Product('plush toy', sku='12-345-6789')
# check content:
p.name # plush toy
p.quantity # -1
p.sku # 12-345-6789
使用以下装饰器代码:
def struct(struct_class):
# create a new init
def struct_init(self, *args, **kwargs):
i = 0 # we really don't need enumerate() here...
for value in args:
name = member_names[i]
default_value = member_values[i]
setattr(self, name, value if value is not None else default_value)
i += 1 # ...we just need to inc an int
for key,value in kwargs.items():
i = member_names.index(key)
default_value = member_values[i]
setattr(self, key, value if value is not None else default_value)
# extract the struct members
member_names = []
member_values = []
for attr_name in dir(struct_class):
if not attr_name.startswith('_'):
value = getattr(struct_class, attr_name)
if not callable(value):
member_names.append(attr_name)
member_values.append(value)
# rebind and return
struct_class.init = struct_init
return struct_class
它的工作原理是获取类,提取字段名及其默认值,然后重写类的__init__函数,根据知道哪个参数索引映射到哪个属性名来设置self属性。
其他回答
更新:数据类
随着Python 3.7中数据类的引入,我们已经非常接近了。
下面的示例与下面的NamedTuple示例类似,但是生成的对象是可变的,并且允许使用默认值。
from dataclasses import dataclass
@dataclass
class Point:
x: float
y: float
z: float = 0.0
p = Point(1.5, 2.5)
print(p) # Point(x=1.5, y=2.5, z=0.0)
如果您想使用更特定的类型注释,这可以很好地配合新的类型模块。
我一直在绝望地等待这一刻!要我说,Data Classes和新的NamedTuple声明,再加上typing模块,简直就是天赐之物!
改进的NamedTuple声明
自从Python 3.6以来,它变得非常简单和美丽(恕我直言),只要你能忍受不变性。
引入了一种声明NamedTuples的新方法,它也允许类型注释:
from typing import NamedTuple
class User(NamedTuple):
name: str
class MyStruct(NamedTuple):
foo: str
bar: int
baz: list
qux: User
my_item = MyStruct('foo', 0, ['baz'], User('peter'))
print(my_item) # MyStruct(foo='foo', bar=0, baz=['baz'], qux=User(name='peter'))
dF:太酷了……我没有 我知道我可以访问的领域 一个使用字典的类。 马克:我希望我遇到的情况 这正是我需要一个元组的时候 但没有什么比 字典。
你可以使用字典访问类的字段,因为类的字段、它的方法和它的所有属性都是用字典存储在内部的(至少在CPython中是这样)。
...这就引出了你的第二个评论。相信Python字典是“沉重的”是一个非常非Python主义的概念。读这样的评论简直要了我的Python禅。这可不太好。
您可以看到,当您声明一个类时,实际上是在为一个字典创建一个相当复杂的包装器——因此,如果有的话,您比使用一个简单的字典增加了更多的开销。顺便说一下,这种开销在任何情况下都是没有意义的。如果您正在处理性能关键的应用程序,请使用C或其他语言。
也许你正在寻找没有构造函数的struct:
class Sample:
name = ''
average = 0.0
values = None # list cannot be initialized here!
s1 = Sample()
s1.name = "sample 1"
s1.values = []
s1.values.append(1)
s1.values.append(2)
s1.values.append(3)
s2 = Sample()
s2.name = "sample 2"
s2.values = []
s2.values.append(4)
for v in s1.values: # prints 1,2,3 --> OK.
print v
print "***"
for v in s2.values: # prints 4 --> OK.
print v
您可以子类化标准库中可用的C结构。ctypes模块提供了一个Structure类。文档中的例子:
>>> from ctypes import *
>>> class POINT(Structure):
... _fields_ = [("x", c_int),
... ("y", c_int)]
...
>>> point = POINT(10, 20)
>>> print point.x, point.y
10 20
>>> point = POINT(y=5)
>>> print point.x, point.y
0 5
>>> POINT(1, 2, 3)
Traceback (most recent call last):
File "<stdin>", line 1, in ?
ValueError: too many initializers
>>>
>>> class RECT(Structure):
... _fields_ = [("upperleft", POINT),
... ("lowerright", POINT)]
...
>>> rc = RECT(point)
>>> print rc.upperleft.x, rc.upperleft.y
0 5
>>> print rc.lowerright.x, rc.lowerright.y
0 0
>>>
有一个python包正是用于此目的。看到cstruct2py
cstruct2py是一个纯python库,用于从C代码生成python类,并使用它们来打包和解包数据。该库可以解析C头文件(结构体、联合、枚举和数组声明),并在python中模拟它们。生成的python类可以解析和打包数据。
例如:
typedef struct {
int x;
int y;
} Point;
after generating pythonic class...
p = Point(x=0x1234, y=0x5678)
p.packed == "\x34\x12\x00\x00\x78\x56\x00\x00"
如何使用
首先,我们需要生成python结构体:
import cstruct2py
parser = cstruct2py.c2py.Parser()
parser.parse_file('examples/example.h')
现在我们可以从C代码中导入所有的名称:
parser.update_globals(globals())
我们也可以直接这样做:
A = parser.parse_string('struct A { int x; int y;};')
使用C代码中的类型和定义
a = A()
a.x = 45
print a
buf = a.packed
b = A(buf)
print b
c = A('aaaa11112222', 2)
print c
print repr(c)
输出将是:
{'x':0x2d, 'y':0x0}
{'x':0x2d, 'y':0x0}
{'x':0x31316161, 'y':0x32323131}
A('aa111122', x=0x31316161, y=0x32323131)
克隆
对于克隆cstruct2py运行:
git clone https://github.com/st0ky/cstruct2py.git --recursive