Python 中的类 C 结构

2025-02-18 09:23:00
admin
原创
112
摘要:问题描述:有没有办法在 Python 中方便地定义类似 C 的结构?我厌倦了写这样的东西:class MyStruct(): def __init__(self, field1, field2, field3): self.field1 = field1 self.fi...

问题描述:

有没有办法在 Python 中方便地定义类似 C 的结构?我厌倦了写这样的东西:

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

解决方案 1:

更新:数据类

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

如果您想使用更具体的类型注释,这可以与新的类型模块很好地配合。

我一直在焦急地等待这个!如果你问我,数据类和新的NamedTuple声明,加上类型模块,简直是天赐之物!

改进的 NamedTuple 声明

自Python 3.6以来,它变得非常简单和美观(IMHO),只要你能接受不变性

引入了一种声明 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'))

解决方案 2:

使用命名元组,它已添加到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")

解决方案 3:

您可以使用元组来做很多事情,而在 C 中您会使用结构体(例如 x、y 坐标或 RGB 颜色)。

对于其他所有事情,您可以使用字典或像这样的实用程序类:

>>> class Bunch:
...     def __init__(self, **kwds):
...         self.__dict__.update(kwds)
...
>>> mystruct = Bunch(field1=value1, field2=value2)

我认为“权威”的讨论就在这里,在 Python Cookbook 的已发布版本中。

解决方案 4:

也许您正在寻找没有构造函数的结构:

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

解决方案 5:

那么字典怎么样?

像这样:

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

然后你可以使用它来操纵值:

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

而且值不一定是字符串。它们可以是任何其他对象。

解决方案 6:

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

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

一定要检查有关插槽的文档,但对插槽的简单解释是,这是 python 的说法:“如果您可以锁定这些属性,并且只能将这些属性锁定到类中,以便您承诺在实例化类后不会添加任何新属性(是的,您可以向类实例添加新属性,请参阅下面的示例)然后,我将取消允许向类实例添加新属性的大型内存分配,而仅使用这些插槽属性所需的内容”。

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

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

输出:AttributeError:'Point' 对象没有属性 'z'

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

解决方案 7:

dF:这太酷了...我不知道我可以使用字典访问类中的字段。

马克:我希望有这种情况,正是当我想要一个元组,但又不需要像字典那样“重”的东西的时候。

您可以使用字典访问类的字段,因为类的字段、其方法和所有属性都是使用字典在内部存储的(至少在 CPython 中)。

...这引出了你的第二条评论。认为 Python 字典很“重”是一种非常不符合 Python 主义的观点。阅读这样的评论会毁了我的 Python 禅意。这可不好。

你看,当你声明一个类时,你实际上是在创建一个非常复杂的字典包装器 - 所以,如果有的话,你会比使用一个简单的字典增加更多的开销。顺便说一句,这种开销在任何情况下都是没有意义的。如果你正在开发性能至关重要的应用程序,请使用 C 或其他语言。

解决方案 8:

您可以将标准库中可用的 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
>>>

解决方案 9:

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

# 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

解决方案 10:

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

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'])

当您需要“不是类的数据包”时,以及命名元组难以理解时,这非常方便......

解决方案 11:

这里的一些答案非常详细。我发现的最简单的选项是(来自: 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

编辑:抱歉,没有看到下面的这个例子。

解决方案 12:

您可以通过以下方式访问 Python 中的 C 风格结构。

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)

注意:请使用您的结构名称代替“cstruct”名称,而不是var_i,var_f,var_str,请定义您的结构的成员变量。

解决方案 13:

我在这里没有看到这个答案,所以我想我会添加它,因为我现在正在学习 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

现在你至少可以一眼就看到程序需要哪些字段。

两者都容易出现拼写错误,但john.slarly = 1000都会成功。不过,它还是有效的。

解决方案 14:

这可能有点晚了,但我使用 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
>>> 

解决方案 15:

我编写了一个装饰器,您可以在任何方法上使用它,以便将传入的所有参数或任何默认值分配给实例。

def argumentsToAttributes(method):
    argumentNames = method.func_code.co_varnames[1:]

    # Generate a dictionary of default values:
    defaultsDict = {}
    defaults = method.func_defaults if method.func_defaults else ()
    for i, default in enumerate(defaults, start = len(argumentNames) - len(defaults)):
        defaultsDict[argumentNames[i]] = default

    def newMethod(self, *args, **kwargs):
        # Use the positional arguments.
        for name, value in zip(argumentNames, args):
            setattr(self, name, value)

        # Add the key word arguments. If anything is missing, use the default.
        for name in argumentNames[len(args):]:
            setattr(self, name, kwargs.get(name, defaultsDict[name]))

        # Run whatever else the method needs to do.
        method(self, *args, **kwargs)

    return newMethod

快速演示。请注意,我使用位置参数a,使用 的默认值b,以及命名参数c。然后我打印所有 3 个引用self,以显示在输入方法之前已正确分配它们。

class A(object):
    @argumentsToAttributes
    def __init__(self, a, b = 'Invisible', c = 'Hello'):
        print(self.a)
        print(self.b)
        print(self.c)

A('Why', c = 'Nothing')

请注意,我的装饰器应该适用于任何方法,而不仅仅是__init__

解决方案 16:

这是一个使用类(从未实例化)来保存数据的解决方案。我喜欢这种方式,因为它只需要很少的输入,并且不需要任何额外的包等。

class myStruct:
    field1 = "one"
    field2 = "2"

稍后您可以根据需要添加更多字段:

myStruct.field3 = 3

为了获取值,可以像平常一样访问字段:

>>> myStruct.field1
'one'

解决方案 17:

这是一个快速而又肮脏的技巧:

>>> ms = Warning()
>>> ms.foo = 123
>>> ms.bar = 'akafrit'

它是如何工作的?它只是重新使用内置类Warning(派生自Exception)并将其用作您自己定义的类。

好处是您不需要先导入或定义任何东西,“警告”是一个简称,而且它还清楚地表明您正在做一些肮脏的事情,这些事情不应该在您的小脚本之外的其他地方使用。

顺便说一句,我试图找到更简单的方法ms = object(),但找不到(最后一个例子不起作用)。如果你有,我很感兴趣。

解决方案 18:

NamedTuple很舒服,但是没有人共享性能和存储。

from typing import NamedTuple
import guppy  # pip install guppy
import timeit


class User:
    def __init__(self, name: str, uid: int):
        self.name = name
        self.uid = uid


class UserSlot:
    __slots__ = ('name', 'uid')

    def __init__(self, name: str, uid: int):
        self.name = name
        self.uid = uid


class UserTuple(NamedTuple):
    # __slots__ = ()  # AttributeError: Cannot overwrite NamedTuple attribute __slots__
    name: str
    uid: int


def get_fn(obj, attr_name: str):
    def get():
        getattr(obj, attr_name)
    return get
if 'memory test':
    obj = [User('Carson', 1) for _ in range(1000000)]      # Cumulative: 189138883
    obj_slot = [UserSlot('Carson', 1) for _ in range(1000000)]          # 77718299  <-- winner
    obj_namedtuple = [UserTuple('Carson', 1) for _ in range(1000000)]   # 85718297
    print(guppy.hpy().heap())  # Run this function individually. 
    """
    Index  Count   %     Size   % Cumulative  % Kind (class / dict of class)
     0 1000000    24 112000000 34 112000000  34 dict of __main__.User
     1 1000000    24 64000000  19 176000000  53 __main__.UserTuple
     2 1000000    24 56000000  17 232000000  70 __main__.User
     3 1000000    24 56000000  17 288000000  87 __main__.UserSlot
     ...
    """

if 'performance test':
    obj = User('Carson', 1)
    obj_slot = UserSlot('Carson', 1)
    obj_tuple = UserTuple('Carson', 1)

    time_normal = min(timeit.repeat(get_fn(obj, 'name'), repeat=20))
    print(time_normal)  # 0.12550550000000005

    time_slot = min(timeit.repeat(get_fn(obj_slot, 'name'), repeat=20))
    print(time_slot)  # 0.1368690000000008

    time_tuple = min(timeit.repeat(get_fn(obj_tuple, 'name'), repeat=20))
    print(time_tuple)  # 0.16006120000000124

    print(time_tuple/time_slot)  # 1.1694481584580898  # The slot is almost 17% faster than NamedTuple on Windows. (Python 3.7.7)

如果您__dict__不使用,请在__slots__(更高性能和存储)和NamedTuple(清除以进行阅读和使用)之间进行选择

您可以查看此链接(插槽的使用)以获取更多__slots__信息。

解决方案 19:

就我个人而言,我也喜欢这个变体。它扩展了@dF 的答案。

class struct:
    def __init__(self, *sequential, **named):
        fields = dict(zip(sequential, [None]*len(sequential)), **named)
        self.__dict__.update(fields)
    def __repr__(self):
        return str(self.__dict__)

它支持两种初始化模式(可以混合):

# Struct with field1, field2, field3 that are initialized to None.
mystruct1 = struct("field1", "field2", "field3") 
# Struct with field1, field2, field3 that are initialized according to arguments.
mystruct2 = struct(field1=1, field2=2, field3=3)

此外,它的打印效果也更好:

print(mystruct2)
# Prints: {'field3': 3, 'field1': 1, 'field2': 2}

解决方案 20:

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

解决方案 21:

以下结构体解决方案的灵感来自 namedtuple 实现和一些先前的答案。但是,与 namedtuple 不同,它的值是可变的,但与 c 样式结构体一样,其名称/属性是不可变的,而普通类或字典则不是。

_class_template = """\nclass {typename}:
def __init__(self, *args, **kwargs):
    fields = {field_names!r}

    for x in fields:
        setattr(self, x, None)            

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

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

def __repr__(self):
    return str(vars(self))

def __setattr__(self, name, value):
    if name not in {field_names!r}:
        raise KeyError("invalid name: %s" % name)
    object.__setattr__(self, name, value)            
"""

def struct(typename, field_names):

    class_definition = _class_template.format(
        typename = typename,
        field_names = field_names)

    namespace = dict(__name__='struct_%s' % typename)
    exec(class_definition, namespace)
    result = namespace[typename]
    result._source = class_definition

    return result

用法:

Person = struct('Person', ['firstname','lastname'])
generic = Person()
michael = Person('Michael')
jones = Person(lastname = 'Jones')


In [168]: michael.middlename = 'ben'
Traceback (most recent call last):

  File "<ipython-input-168-b31c393c0d67>", line 1, in <module>
michael.middlename = 'ben'

  File "<string>", line 19, in __setattr__

KeyError: 'invalid name: middlename'

解决方案 22:

有一个专门用于此目的的 Python 包。请参阅cstruct2py

cstruct2py是一个纯 Python 库,用于从 C 代码生成 Python 类并使用它们打包和解包数据。该库可以解析 C 头文件(结构、联合、枚举和数组声明)并在 Python 中模拟它们。生成的 Pythonic 类可以解析和打包数据。

例如:

typedef struct {
  int x;
  int y;
} Point;

after generating pythonic class...
p = Point(x=0x1234, y=0x5678)
p.packed == "x34x12x00x00x78x56x00x00"

如何使用

首先我们需要生成 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

解决方案 23:

如果您没有 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)

解决方案 24:

我发现最好的方法是使用自定义字典类,如下文所述: https: //stackoverflow.com/a/14620633/8484485

如果需要 iPython 自动完成支持,只需像这样定义dir () 函数:

class AttrDict(dict):
    def __init__(self, *args, **kwargs):
        super(AttrDict, self).__init__(*args, **kwargs)
        self.__dict__ = self
    def __dir__(self):
        return self.keys()

然后像这样定义伪结构:(这个是嵌套的)

my_struct=AttrDict ({
    'com1':AttrDict ({
        'inst':[0x05],
        'numbytes':2,
        'canpayload':False,
        'payload':None
    })
})

然后您可以像这样访问 my_struct 内的值:

print(my_struct.com1.inst)

=>[5]

解决方案 25:

我能想到的最干净的方法是使用类装饰器,它允许您声明一个静态类并将其重写为具有普通命名属性的结构:

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以根据了解哪个参数索引映射到哪个属性名称来设置属性。

解决方案 26:

我觉得Python结构字典适合这个要求。

d = dict{}
d[field1] = field1
d[field2] = field2
d[field2] = field3

解决方案 27:

扩展@gz。(通常优于这个)的答案,对于一个快速而肮脏的namedtuple结构,我们可以这样做:

import collections

x = collections.namedtuple('foobar', 'foo bar')(foo=1,bar=2)
y = collections.namedtuple('foobar', 'foo bar')(foo=3,bar=4)
print(x,y)

>foobar(foo=1, bar=2) foobar(foo=3, bar=4)

解决方案 28:

Python 中简单且安全的类 C 结构、点访问 ( my_struct.my_var) 容器

1. 最简单和最自文档化之间的良好平衡是具有预定义self成员的类

一个简单而有效的方法是定义一个带有预定义成员的类,就像这样。这样,类的用户就可以轻松看到你希望在其中放入什么!

如果您想要一个预填充成员的构造函数,您也可以这样做,但我明确避免这样做,以便不必全部输入。通常我不需要“构造函数”,因此编写起来更简单、更快:

class MyStruct():
    def __init__(self):
        # predefined members expected to be used in this class
        self.name = None
        self.x = None
        self.y = None
        self.z = None
        self.is_ready = False

然后,你可以像这样使用它:

# Construct an instance of the class, `MyStruct`
my_data = MyStruct()
# Add any variables or values you want to it
my_data.name = "Some useful name of this data"
my_data.x = 123
my_data.y = 456
my_data.z = 789.001
my_data.is_ready = True

# You are not limited to those members, you can actually arbitrarily add any 
# members you want to it at run-time
my_data.some_other_var = "Some other value"
my_data.whatever = 35
# etc. 

2.最简单的就是空类

...像这样:

class AnyStruct():
    pass

我厌倦了写这样的东西:

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

从技术上讲,您不必编写所有这些。最简单的类只包含pass。而且,Python 中的类自然类似于 C 结构,并且可以在运行时任意添加任何数据。因此,只需执行以下操作:

# Create a universal C-struct-like class
class AnyStruct():
    pass

# Make a universal print function to print all user-added members of any class 
# like this:
def print_any_class(class_instance):
    """
    Print all members of a class.
    """
    for key, value in class_instance.__dict__.items():
        print(f"{key}: {value}")
    print()

# Construct an instance of the C-struct-like class, `AnyStruct`
my_data = AnyStruct()

# Add any variables or values you want to it, at run-time
my_data.name = "Some useful name of this data"
my_data.x = 123
my_data.y = 456
my_data.z = 789.001
my_data.is_ready = True

# Print it
print_any_class(my_data)

输出:

name: Some useful name of this data
x: 123
y: 456
z: 789.001
is_ready: True

参考

  1. 我的示例程序,struct_c_like.py在我的eRCaGuy_hello_world repo 中。

  2. 我与 GitHub CoPilot 进行了交流,以帮助我学习上述一些技术,例如迭代字典和了解是否.__dict__存在。不过,上述所有文字和代码都是我自己的。

相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   3938  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   2732  
  本文介绍了以下10款项目管理软件工具:禅道项目管理软件、Freshdesk、ClickUp、nTask、Hubstaff、Plutio、Productive、Targa、Bonsai、Wrike。在当今快速变化的商业环境中,项目管理已成为企业成功的关键因素之一。然而,许多企业在项目管理过程中面临着诸多痛点,如任务分配不...
项目管理系统   72  
  本文介绍了以下10款项目管理软件工具:禅道项目管理软件、Monday、TeamGantt、Filestage、Chanty、Visor、Smartsheet、Productive、Quire、Planview。在当今快速变化的商业环境中,项目管理已成为企业成功的关键因素之一。然而,许多项目经理和团队在管理复杂项目时,常...
开源项目管理工具   79  
  本文介绍了以下10款项目管理软件工具:禅道项目管理软件、Smartsheet、GanttPRO、Backlog、Visor、ResourceGuru、Productive、Xebrio、Hive、Quire。在当今快节奏的商业环境中,项目管理已成为企业成功的关键因素之一。然而,许多企业在选择项目管理工具时常常面临困惑:...
项目管理系统   66  
热门文章
项目管理软件有哪些?
曾咪二维码

扫码咨询,免费领取项目管理大礼包!

云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用