是否有一种方法可以方便地在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'])

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

其他回答

每当我需要一个“行为像字典一样的即时数据对象”(我不会想到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'])

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

https://stackoverflow.com/a/32448434/159695在Python3中不起作用。

https://stackoverflow.com/a/35993/159695在Python3中工作。

然后我扩展它来添加默认值。

class myStruct:
    def __init__(self, **kwds):
        self.x=0
        self.__dict__.update(kwds) # Must be last to accept assigned member variable.
    def __repr__(self):
        args = ['%s=%s' % (k, repr(v)) for (k,v) in vars(self).items()]
        return '%s(%s)' % ( self.__class__.__qualname__, ', '.join(args) )

a=myStruct()
b=myStruct(x=3,y='test')
c=myStruct(x='str')

>>> a
myStruct(x=0)
>>> b
myStruct(x=3, y='test')
>>> c
myStruct(x='str')

我还想添加一个使用插槽的解决方案:

class Point:
    __slots__ = ["x", "y"]
    def __init__(self, x, y):
        self.x = x
        self.y = y

Definitely check the documentation for slots but a quick explanation of slots is that it is python's way of saying: "If you can lock these attributes and only these attributes into the class such that you commit that you will not add any new attributes once the class is instantiated (yes you can add new attributes to a class instance, see example below) then I will do away with the large memory allocation that allows for adding new attributes to a class instance and use just what I need for these slotted attributes".

添加属性到类实例的例子(因此不使用插槽):

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

p1 = Point(3,5)
p1.z = 8
print(p1.z)

输出:8

尝试向使用插槽的类实例添加属性的示例:

class Point:
    __slots__ = ["x", "y"]
    def __init__(self, x, y):
        self.x = x
        self.y = y

p1 = Point(3,5)
p1.z = 8

'Point'对象没有属性'z'

这可以有效地作为结构体工作,并且比类使用更少的内存(就像结构体一样,尽管我没有研究具体有多少内存)。如果要创建对象的大量实例且不需要添加属性,建议使用slot。点对象就是一个很好的例子,因为很可能会实例化许多点来描述一个数据集。

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

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属性。

一本字典怎么样?

就像这样:

myStruct = {'field1': 'some val', 'field2': 'some val'}

然后你可以使用这个来操作值:

print myStruct['field1']
myStruct['field2'] = 'some other values'

值不一定是字符串。它们可以是其他任何物体。