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

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

当前回答

你可以通过以下方式在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。

其他回答

一本字典怎么样?

就像这样:

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

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

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

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

这可能有点晚了,但我使用Python元类(下面也有装饰器版本)做了一个解决方案。

当__init__在运行时被调用时,它会获取每个参数及其值,并将它们作为实例变量分配给你的类。通过这种方式,您可以创建一个类结构的类,而不必手动分配每个值。

我的例子没有错误检查,所以更容易遵循。

class MyStruct(type):
    def __call__(cls, *args, **kwargs):
        names = cls.__init__.func_code.co_varnames[1:]

        self = type.__call__(cls, *args, **kwargs)

        for name, value in zip(names, args):
            setattr(self , name, value)

        for name, value in kwargs.iteritems():
            setattr(self , name, value)
        return self 

这是它的行动。

>>> class MyClass(object):
    __metaclass__ = MyStruct
    def __init__(self, a, b, c):
        pass


>>> my_instance = MyClass(1, 2, 3)
>>> my_instance.a
1
>>> 

我把它发布在reddit上,/u/matchu发布了一个更干净的装饰版本。我鼓励您使用它,除非您想扩展元类版本。

>>> def init_all_args(fn):
    @wraps(fn)
    def wrapped_init(self, *args, **kwargs):
        names = fn.func_code.co_varnames[1:]

        for name, value in zip(names, args):
            setattr(self, name, value)

        for name, value in kwargs.iteritems():
            setattr(self, name, value)

    return wrapped_init

>>> class Test(object):
    @init_all_args
    def __init__(self, a, b):
        pass


>>> a = Test(1, 2)
>>> a.a
1
>>> 

如果您没有3.7的@dataclass,并且需要可变性,那么下面的代码可能适合您。它是非常自文档化和ide友好的(自动完成),防止编写两次内容,易于扩展,并且非常简单地测试所有实例变量都被完全初始化:

class Params():
    def __init__(self):
        self.var1 : int = None
        self.var2 : str = None

    def are_all_defined(self):
        for key, value in self.__dict__.items():
            assert (value is not None), "instance variable {} is still None".format(key)
        return True


params = Params()
params.var1 = 2
params.var2 = 'hello'
assert(params.are_all_defined)

更新:数据类

随着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'))

我在这里没有看到这个答案,所以我想我将添加它,因为我现在正在学习Python,并且刚刚发现它。Python教程(在本例中是Python 2)给出了以下简单而有效的示例:

class Employee:
    pass

john = Employee()  # Create an empty employee record

# Fill the fields of the record
john.name = 'John Doe'
john.dept = 'computer lab'
john.salary = 1000

也就是说,创建一个空类对象,然后实例化,动态添加字段。

这样做的好处是非常简单。缺点是它不是特别自记录的(在类“定义”中没有列出预期的成员),并且未设置字段在访问时可能会导致问题。这两个问题可以通过以下方法解决:

class Employee:
    def __init__ (self):
        self.name = None # or whatever
        self.dept = None
        self.salary = None

现在,您至少可以一目了然地看到程序将期望哪些字段。

两者都很容易打错别字,约翰。Slarly = 1000将成功。不过,它还是有效的。