Is there a data type in Python similar to structs in C++?

Question:

Is there a data type in Python similar to structs in C++? I like the struct feature myStruct.someName. I know that classes have this, but I don’t want to write a class everytime I need a “container” for some data.

Asked By: Aufwind

||

Answers:

Why not? Classes are fine for that.

If you want to save some memory, you might also want to use __slots__ so the objects don’t have a __dict__. See http://docs.python.org/reference/datamodel.html#slots for details and Usage of __slots__? for some useful information.

For example, a class holding only two values (a and b) could looks like this:

class AB(object):
    __slots__ = ('a', 'b')

If you actually want a dict but with obj.item access instead of obj['item'], you could subclass dict and implement __getattr__ and __setattr__ to behave like __getitem__ and __setitem__.

Answered By: ThiefMaster

I believe you’re looking for a dict.

d = dict({
        'name': 'myname',
        'val': 'myval'
        })

print d
print d['name']
Answered By: Demian Brecht

Try using a dict.

Here’s a simplistic demonstration.

>>> something = {}
>>> something['x'] = 42
>>> something['y'] = 'cheese'
>>> something
{'y': 'cheese', 'x': 42}
>>> something['x']
42
>>> something['y']
'cheese'
Answered By: johnsyweb

Please realise that in C++, the only difference between a class and a struct is that the elements of a class are by default private, as is the inheritance. The following are equivalent:

class D : public B {
    public:
    ...
}; 

struct D {
    ...
};

In Python, it would make most sense to use a class if you want to use the dot operator to access elements. In fact, it’s even easier, as you only have to initialise the members you currently want, and can add/remove members later. Therefore, the following would work:

class D(object):
    pass

You can then add as many members as you want simply by assigning to them.

Answered By: Anton Golov

You can always go for the dynamic approach:

class foo(object):
    def __init__(self,**kwargs):
        self.__dict__.update(kwargs)

This’ll make a class with the same methods that you pass in as a dict:

bar = foo(bill="yo",heather="hi",sam="piss off")

leaving you with the following perfectly valid calls on bar:

bar.bill
>> "yo"
bar.heater
>> "hi"

you get the idea…

Answered By: wheaties

In addition to the dict type, there is a namedtuple type that behaves somewhat like a struct.

MyStruct = namedtuple('MyStruct', ['someName', 'anotherName'])
aStruct = MyStruct('aValue', 'anotherValue')

print aStruct.someName, aStruct.anotherName
Answered By: sock

This may be taking the idea a bit too far, but here’s a way to create “structs” using a syntax that’s kinda similar to C++ structs that also does some type checking. First, here’s an example of using it:

>>> MyStruct = Struct({
...     'i': int,
...     's': str,
...     'x': float,
... }, 'MyStruct')
>>> print(MyStruct)
MyStruct {
    i: int,
    s: str,
    x: float,
}

>>> instance = MyStruct(i=1, s='s', x=1.0)
>>> print(instance)
MyStruct(i: 1, s: 's', x: 1.0)

And here’s the implementation. It’s a variation of the __slots__ idea where the class with slots (i.e., the “struct” type) is generated dynamically. This could of course be fleshed out in various ways, but this is just a proof of concept.

class Struct:

    class StructInstance:

        __slots__ = ()

        def __str__(self):
            values = []
            for name in self.__slots__:
                value = getattr(self, name)
                values.append('{name}: {value!r}'.format(name=name, value=value))
            type_name = self.__class__.__name__
            values = ', '.join(values)
            return '{type_name}({values})'.format(type_name=type_name, values=values)

    def __init__(self, fields, name=None):
        for field_name, field_type in fields.items():
            assert isinstance(field_name, str), 'Expected str for field name'
            assert isinstance(field_type, type), 'Expected type for field type'
        self.fields = fields
        self.name = name or 'Struct'
        self.type = type(
            self.name, (self.StructInstance,), {'__slots__': tuple(fields)})

    def __call__(self, **values):
        instance = self.type()
        for name in instance.__slots__:
            value = values[name]
            expected_type = self.fields[name]
            assert isinstance(value, expected_type), 'Expected %s for %s' % (expected_type, name)
            setattr(instance, name, value)
        return instance

    def __str__(self):
        fields = ['    {n}: {t.__name__},'.format(n=n, t=t) for n, t in self.fields.items()]
        return '{name} {{n{fields}n}}'.format(name=self.name, fields='n'.join(fields))
Answered By: user8651755

dataclass is now built-in to Python as of Python 3.7!

from dataclasses import dataclass

@dataclass
class EZClass:
    name: str='default'
    qty: int

Test:

classy = EZClass('cars', 3)
print(classy)

Output:

EZClass(name='cars', qty=3)

Besides for the automatic initialization and __repr__ methods which it generates, it also automatically creates an __eq__ method to make it simple and intuitive to compare two instances of the class.

See PEP 557.

Backported to Python 3.6 using the dataclasses package.

Answered By: ChaimG
Categories: questions Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.