Using tuples correctly?

Bengt Richter bokr at
Mon Oct 11 10:13:44 CEST 2004

On Mon, 11 Oct 2004 05:53:47 +0200, =?ISO-8859-1?Q?BJ=F6rn_Lindqvist?= <bjourne at> wrote:

>I like tuples alot. But in some situations you seem to be forced to
>access the elements of a tuple via its indexes and that is pretty
>ugly. For example:
># make_color() returns a rgb tuple (r, g, b). I.e. (255, 0, 0)
>print "The red value is: ", make_color()[0]
>Not nice at all. It is maybe OK for a rgb tuple that only has three
>elements, but for a tuple that has 10+ elements, index access is
>rediculous. In that case, unpacking wont helpe either. What you would
>like to write is:
>print "The red value is: ", make_color().r
>You can get that to work by using this recipe
> from
>the Python Cookbook. Then write this:
>Color =3D superTuple("Color", ["r", "g", "b"])
>def make_color():
>      return Color(12, 24, 48)
>However, then make_color has to assume that there already exists a
>special tuple type named Color. But that assumption is bad and you
>shouldn't need to assume it. You could also write
Why is that bad? You only have to define it once.
>return superTuple("Color", ["r", "g", "b"])(12, 24, 48)
>To create the tuple type and instantiate it at the same type. But it
>is alot to write. You could trim it down to: st("r", "g", "b")(12, 24,
>48) if you want to save your fingers. Still to much and looks kinda
How about
    return Color(12, 24, 48, order='r g b')
    Color.names = 'r g b'.split()  # override names for all instances that don't have order=
    ...                            # above is not even necessary, since that's the initial names value
    return Color(g=24, r=12, b=48) # use names to assign ordered values
    return Color()                 # put zeroes for unspecified values to match names length

etc. See below
>After some more browsing of the Python Cookbook and googling it seems
>like lots of people is trying to emulate structs on the fly in python.
>So why aren't there a tuple-with-named-attributes type in python? So
>you could write stuff like this:
>return (r: 10, g: 20, b: 30) or maybe return (.r 10, .g 20, .b 30)
>Clearly, I must be thinking wrong or it would already be implemented
>in python. Atleast there would have been a PEP for it. Maybe I'm just
>using tuples incorrectly and that is why my code uses index access to
>tuples? Someone must have already thought about this and they must
>have discussed it and quickly realized that this is A Very Bad Thing.
>But why?  I'm new, so please dont get to angry if the answer is

Not sure what you are needing, but consider yet another class:
(not a speed demon, and not tested beyond what you see below ;-)

 >>> class Color(tuple):
 ...     names = 'r g b'.split()
 ...     def __new__(cls, *args, **kw):
 ...         values = list(args)
 ...         onames = kw.get('order','').split()
 ...         names = onames or cls.names
 ...         if len(names)>len(values): values.extend([0]*(len(names)-len(values)))
 ...         assert len(names)<=len(values)
 ...         for i, name in enumerate(names):
 ...             if name in kw: values[i] = kw.get(name)
 ...         inst = tuple.__new__(cls, values)
 ...         if onames: inst.names=onames
 ...         return inst
 ...     def __getattr__(self, name):
 ...         try: i = object.__getattribute__(self, 'names').index(name)
 ...         except ValueError: raise AttributeError, 'No component named %r'%name
 ...         return tuple.__getitem__(self, i)
 >>> rgb = Color(1,2,3)
 >>> rgb
 (1, 2, 3)
 >>> rgb.b, rgb.g, rgb.r #in reverse
 (3, 2, 1)
 >>> c0 = Color()
 >>> c0
 (0, 0, 0)
 >>> zip(c0.names, c0)
 [('r', 0), ('g', 0), ('b', 0)]
 >>> c2 = Color(b=33,g=22)
 >>> c2
 (0, 22, 33)
 >>> c3 = Color(red=111, alpha=.5, order='alpha red green blue')
 >>> c3
 (0.5, 111, 0, 0)
 >>> rgb
 (1, 2, 3)
 >>> rgb.g
 >>> c3.alpha

Maybe some ideas for what you really want ?;-)
Probably overlaps other super-tuples a fair amount. I didn't look.

Bengt Richter

More information about the Python-list mailing list