是否有一种方法可以方便地在Python中定义类c结构?我厌倦了写这样的东西:

class MyStruct():
    def __init__(self, field1, field2, field3):
        self.field1 = field1
        self.field2 = field2
        self.field3 = field3

当前回答

每当我需要一个“行为像字典一样的即时数据对象”(我不会想到C结构体!),我就会想到这个可爱的hack:

class Map(dict):
    def __init__(self, **kwargs):
        super(Map, self).__init__(**kwargs)
        self.__dict__ = self

现在你可以说:

struct = Map(field1='foo', field2='bar', field3=42)

self.assertEquals('bar', struct.field2)
self.assertEquals(42, struct['field3'])

当你需要一个“不是类的数据包”的时候,非常方便,当命名元组是不可理解的……

其他回答

这里的一些答案非常详尽。我找到的最简单的选项是(from: http://norvig.com/python-iaq.html):)

class Struct:
    "A structure that can have any fields defined."
    def __init__(self, **entries): self.__dict__.update(entries)

初始化:

>>> options = Struct(answer=42, linelen=80, font='courier')
>>> options.answer
42

添加更多的:

>>> options.cat = "dog"
>>> options.cat
dog

编辑:对不起,没有看到这个例子已经进一步。

我能想到的最干净的方法是使用一个类装饰器,它可以让你声明一个静态类,并将其重写为一个具有正常命名属性的结构体:

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中访问C-Style struct。

class cstruct:
    var_i = 0
    var_f = 0.0
    var_str = ""

如果你只想使用cstruct的对象

obj = cstruct()
obj.var_i = 50
obj.var_f = 50.00
obj.var_str = "fifty"
print "cstruct: obj i=%d f=%f s=%s" %(obj.var_i, obj.var_f, obj.var_str)

如果你想创建一个cstruct对象的数组

obj_array = [cstruct() for i in range(10)]
obj_array[0].var_i = 10
obj_array[0].var_f = 10.00
obj_array[0].var_str = "ten"

#go ahead and fill rest of array instaces of struct

#print all the value
for i in range(10):
    print "cstruct: obj_array i=%d f=%f s=%s" %(obj_array[i].var_i, obj_array[i].var_f, obj_array[i].var_str)

注意: 请使用你的struct名称,而不是'cstruct'名称 请定义结构的成员变量,而不是var_i, var_f, var_str。

使用命名元组,该元组被添加到Python 2.6标准库中的collections模块中。如果你需要支持Python 2.4,也可以使用Raymond Hettinger的命名元组配方。

它适用于基本示例,但也适用于稍后可能遇到的一些边缘情况。你上面的片段可以写成:

from collections import namedtuple
MyStruct = namedtuple("MyStruct", "field1 field2 field3")

新创建的类型可以这样使用:

m = MyStruct("foo", "bar", "baz")

你也可以使用命名参数:

m = MyStruct(field1="foo", field2="bar", field3="baz")

还可以按位置将初始化参数传递给实例变量

# Abstract struct class       
class Struct:
    def __init__ (self, *argv, **argd):
        if len(argd):
            # Update by dictionary
            self.__dict__.update (argd)
        else:
            # Update by position
            attrs = filter (lambda x: x[0:2] != "__", dir(self))
            for n in range(len(argv)):
                setattr(self, attrs[n], argv[n])

# Specific class
class Point3dStruct (Struct):
    x = 0
    y = 0
    z = 0

pt1 = Point3dStruct()
pt1.x = 10

print pt1.x
print "-"*10

pt2 = Point3dStruct(5, 6)

print pt2.x, pt2.y
print "-"*10

pt3 = Point3dStruct (x=1, y=2, z=3)
print pt3.x, pt3.y, pt3.z
print "-"*10