Using tuples correctly?

  • Thread starter =?ISO-8859-1?Q?BJ=F6rn_Lindqvist?=
  • Start date
?

=?ISO-8859-1?Q?BJ=F6rn_Lindqvist?=

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
http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/218485 from
the Python Cookbook. Then write this:

Color = 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

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
awkward.

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
obvious.
 
B

Bengt Richter

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
http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/218485 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
awkward.
How about
return Color(12, 24, 48, order='r g b')
or
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
or
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
obvious.

Not sure what you are needing, but consider yet another class:
(not a speed demon, and not tested beyond what you see below ;-)
... 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 = 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 2
>>> c3.green 0
>>> c3.alpha
0.5

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

Regards,
Bengt Richter
 
?

=?ISO-8859-1?Q?BJ=F6rn_Lindqvist?=

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

[snip]

That is all very nice but doesn't get around the fact that either you
declare your objects, or you suffer index access.
 
A

Alex Martelli

BJörn Lindqvist said:
So why aren't there a tuple-with-named-attributes type in python? So

Good question. Tuple-like thingies with named attrs have been
introduced reasonably recently (e.g. as the return types for modules in
the stdlib such as time and os.stat) but not generalized.
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

I think it's just that nobody has yet bothered to write a PEP (and do
all the research and experimentation that goes with it).
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
obvious.

It's not obvious to _me_. In Python 2.5 (too late for 2.4) we COULD
conceivably have such a type, if somebody comes up with a _very_
convincing design for it (the use case is already pretty well
established by the precedents in os.stat and module time, we only need
an obviously great design;-). New syntax for it, I'd rule out (smells
like the language will be near-frozen in 2.4 -> 2.5, as it was in 2.2 ->
2.3 -- I could be guessing wrong on this, of course).

Something like tuple(r=10, g=20, b=30) won't wash because keyword args
are passed as a dict -- orderless. Pity, because apart from this it
would be neat... tuple would have to keep a cache of tuple subtypes
indexed by attrnames ('r', 'g', 'b') to avoid making a new type every
time, but that's OK, I think. Maybe an optional first parameter giving
the ordering, as in tuple(('r','g','b'), r=10,g=20,b=30)? It being an
exeception if a different ordering is specified for a set of attribute
names which already exists, and default being 'any order you please'...?
But it feels klunky...:-(. Anyway, this is why the PEP process exists
-- so, a Paladin of the new idea should ask Barry (I think he's still
Pep Czar) for a PEP number and start drafting one.

Use cases and implementation pretty obvious, nothing but a new design to
find... seems pretty simple, as PEPs go...


Alex
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,767
Messages
2,569,572
Members
45,046
Latest member
Gavizuho

Latest Threads

Top