tags:

views:

7952

answers:

10

Is there a way to conveniently define a C-like structure in Python? I'm tired of writing stuff like:

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

(Interesting, it appears I can't type underscores following non-whitespace in pre-formatted text blocks)

A: 

(oh, I take that back about the double underscores... it just shows up funny in the edit preview)

wesc
Please use comments rather than answers for additional information.
Adrian McCarthy
+5  A: 

How about a dictionary?

Something like this:

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

Then you can use this to manipulate values:

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

And the values don't have to be strings. They can be pretty much any other object.

Mark Biek
+1  A: 

(oh, I take that back about the double underscores... it just shows up funny in the edit preview)

Yep, there was just a question about that.

As far as your question goes, why exactly do you want to use a Struct in Python? What are you trying to do? Is there a more 'Pythonic' way of doing it?

Edited to add: It looks like Mark posted a more 'Pythonic' approach while I was writing this

Chris Upchurch
+17  A: 

You can use a tuple for a lot of things where you would use a struct in C (something like x,y coordinates or RGB colors for example).

For everything else you can use dictionary, or a utility class like this one:

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

I think the "definitive" discussion is here, in the published version of the Python Cookbook.

dF
Hey, people want the link but it appears dead. Can you update?
Will
A: 

dF: that's pretty cool... I didn't know that I could access the fields in a class using dict.

Mark: the situations that I wish I had this are precisely when I want a tuple but nothing as "heavy" as a dictionary. For example, suppose I have a function that returns an x,y,z coordinate tuple. I don't want to have to return a dictionary and then need to reference it with indexing rather than just doing something like point.x, point.y, and point.z. Problem with tuples is that their fields are nameless, ie point[0], point[1], and point[2] is not readable.

And it was tough to Google an answer on this, because struct is a Python module. Yay for stackoverflow!

wesc
+12  A: 

For a "whole" solution, see Raymond Hettinger's named tuple recipe. It's nice for your basic example, but also covers a bunch of edge cases you might run into later as well. Your fragment above would be written as:

MyStruct = namedtuple("MyStruct", "field1 field2 field3")

This has the advantage of having been added to the collections module for Python 2.6 so will be one import away in future.

gz
+1 namedtuple is awesome
delnan
+3  A: 

dF: that's pretty cool... I didn't know that I could access the fields in a class using dict.

Mark: the situations that I wish I had this are precisely when I want a tuple but nothing as "heavy" as a dictionary.

You can access the fields of a class using a dictionary because the fields of a class, its methods and all its properties are stored internally using dicts (at least in Cython).

...Which leads us to your second comment. Believing that Python dicts are "heavy" is an extremely non-pythonistic concept. And reading such comments kills my Python Zen. That's not good.

You see, when you declare a class you are actually creating a pretty complex wrapper around a dictionary - so, if anything, you are adding more overhead than by using a simple dictionary. An overhead which, by the way, is meaningless in any case. If you are working on performance critical applications, use C or something.

Vicent Marti
+4  A: 

You can also pass the init parameters to the instance variables by position

# 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
PabloG
A: 

Perhaps you are looking for Structs without constructors:

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
Jose M Balaguer
A: 

I thought that python directories didn't have a specified or fixed order. So the line:

attrs = filter (lambda x: x[0:2] != "__", dir(self))

only works by luck and might break at any time. The class variables might be returned in a different order then the order they were declared in and/or different orders at different times.

python newbe