467,146 Members | 1,257 Online
Bytes | Developer Community
Ask Question

Home New Posts Topics Members FAQ

Post your question to a community of 467,146 developers. It's quick & easy.

Returning a tuple-struct

I've noticed that there's a few functions that return what appears to
be a tuple, but that also has attributes for each item in the tuple.
For example, time.localtime() returns a time.time_struct, which looks
like a tuple but also like a struct. That is, I can do:
time.localtime() (2006, 1, 18, 21, 15, 11, 2, 18, 0) time.localtime()[3] 21 time.localtime().tm_hour

21

Anyway, I guess there's a few of ways to do this. In the case above,
it would seem reasonable to override __getitem__() and other things to
get that result.

To my question... It seems like a useful but very simple way to
accomplish the above (that is, to have your return value accessible as
both a sequence and a struct) is to subclass tuple. Something like
this:

def foo():
class NewTuple(tuple): pass
x = NewTuple((1,2))
x.a, x.b = x
return x

And so I can do:

x = foo()
print x
print x.a
print x.b

And the result is:

(1, 2)
1
2

So, the question I have is just a style and/or pattern question...
Does anyone do this? Does is seem reasonably intuitive, or ugly? Is
there a better way? Thoughts?

-bri

Jan 19 '06 #1
  • viewed: 1481
Share:
6 Replies
gr*****************@spamgourmet.com wrote:
I've noticed that there's a few functions that return what appears to
be a tuple, but that also has attributes for each item in the tuple.
For example, time.localtime() returns a time.time_struct, which looks
like a tuple but also like a struct. That is, I can do:

time.localtime()
(2006, 1, 18, 21, 15, 11, 2, 18, 0)
time.localtime()[3]
21
time.localtime().tm_hour


21

Anyway, I guess there's a few of ways to do this. In the case above,
it would seem reasonable to override __getitem__() and other things to
get that result.

To my question... It seems like a useful but very simple way to
accomplish the above (that is, to have your return value accessible as
both a sequence and a struct) is to subclass tuple. Something like
this:

def foo():
class NewTuple(tuple): pass
x = NewTuple((1,2))
x.a, x.b = x
return x

And so I can do:

x = foo()
print x
print x.a
print x.b

And the result is:

(1, 2)
1
2

So, the question I have is just a style and/or pattern question...
Does anyone do this? Does is seem reasonably intuitive, or ugly? Is
there a better way? Thoughts?

-bri


I think stylistically better might be

class NewTuple(tuple):
def __new__(self, atup):
self.a, self.b = atup[:2]
return tuple.__new__(self, atup)

x = NewTuple((1, 2, 3, 4, 5))
print x
print x.a
print x.b

Jan 19 '06 #2
gr*****************@spamgourmet.com wrote:
time.localtime() (2006, 1, 18, 21, 15, 11, 2, 18, 0) time.localtime()[3] 21 time.localtime().tm_hour 21

Anyway, I guess there's a few of ways to do this. In the case above,
it would seem reasonable to override __getitem__() and other things to
get that result.

I have a generic solution for this (never submitted to the cookbook... should
I?)
import operator
def NamedTuple(*args, **kwargs):
class named_tuple_class(tuple):
pass

values = []
idx = 0
for arg in args:
for name in arg[:-1]:
setattr(named_tuple_class, name,
property(operator.itemgetter(idx)))
values.append(arg[-1])
idx += 1
for name,val in kwargs.iteritems():
setattr(named_tuple_class, name, property(operator.itemgetter(idx)))
values.append(val)
idx += 1

return named_tuple_class(values)

t = NamedTuple(("x", 12), ("y", 18))
t (12, 18) t[0] 12 t.x 12 t[1] 18 t.y 18 t.z Traceback (most recent call last):
File "<stdin>", line 1, in ?
AttributeError: 'named_tuple_class' object has no attribute 'z'

t = NamedTuple(("p", "pos", "position", 12.4))
t (12.4,) t.p 12.4 t.pos 12.4 t.position 12.4
t = NamedTuple(("p", "pos", 12.4), length="foo")
t (12.4, 'foo') t.p 12.4 t.pos 12.4 t.length

'foo'
--
Giovanni Bajo
Jan 19 '06 #3
On Thu, 18 Jan 2006 gr*****************@spamgourmet.com wrote:
Is there a better way? Thoughts?


I was thinking along these lines:

class NamedTuple(tuple):
def __init__(self, indices, values):
"indices should be a map from name to index"
tuple.__init__(self, values)
self.indices = indices
def __getattr__(self, name):
return self[self.indices[name]]

colourNames = {"red": 0, "green": 1, "blue":2}
plum = NamedTuple(colourNames, (219, 55, 121))

The idea is that it's a tuple, but it has some metadata alongside (shared
with other similarly-shaped tuples) which allows it to resolve names to
indices - thus avoiding having two references to everything.

However, if i try that, i get:

Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: tuple() takes at most 1 argument (2 given)

As far as i can tell, inheriting from tuple is forcing my constructor to
only take one argument. Is that the case? If so, anyone got any idea why?

If i rewrite it like this:

class NamedTuple(tuple):
def __init__(self, values):
tuple.__init__(self, values)
def __getattr__(self, name):
return self[self.indices[name]]

class ColourTuple(NamedTuple):
indices = {"red": 0, "green": 1, "blue":2}

plum = ColourTuple((219, 55, 121))

Then it works. This is even an arguably better style. Changing the
constructor to take *values rather than values, and to validate the length
of the value tuple against the length of the index tuple, would be good,
but, since i'm lazy, is left as an exercise to the reader.

tom

--
Throwin' Lyle's liquor away is like pickin' a fight with a meat packing
plant! -- Ray Smuckles
Jan 21 '06 #4
gr*****************@spamgourmet.com wrote:
I've noticed that there's a few functions that return what appears to
be a tuple, but that also has attributes for each item in the tuple.
For example, time.localtime() returns a time.time_struct, which looks
like a tuple but also like a struct. That is, I can do:
time.localtime()(2006, 1, 18, 21, 15, 11, 2, 18, 0) time.localtime()[3]21 time.localtime().tm_hour21


Ah, but it ISN'T really a tuple:
import time
t = time.localtime()
type(t) <type 'time.struct_time'> str(t)

'(2006, 1, 21, 22, 49, 32, 5, 21, 0)'

It's a class object. The __repr__ method returns a string that LOOKS the
same as a tuple.
--
- Tim Roberts, ti**@probo.com
Providenza & Boekelheide, Inc.
Jan 22 '06 #5
Tom Anderson wrote:
On Thu, 18 Jan 2006 gr*****************@spamgourmet.com wrote:
Is there a better way? Thoughts?

I was thinking along these lines:

class NamedTuple(tuple):
def __init__(self, indices, values):
"indices should be a map from name to index"
tuple.__init__(self, values)
self.indices = indices
def __getattr__(self, name):
return self[self.indices[name]]

colourNames = {"red": 0, "green": 1, "blue":2}
plum = NamedTuple(colourNames, (219, 55, 121))

The idea is that it's a tuple, but it has some metadata alongside
(shared with other similarly-shaped tuples) which allows it to resolve
names to indices - thus avoiding having two references to everything.

However, if i try that, i get:

Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: tuple() takes at most 1 argument (2 given)

As far as i can tell, inheriting from tuple is forcing my constructor to
only take one argument. Is that the case? If so, anyone got any idea why?


This error message is not coming from __init__, but from __new__. See

http://www.python.org/2.2/descrintro.html#__new__

James
Jan 23 '06 #6
On Thu, 19 Jan 2006 10:47:35 GMT, rumours say that "Giovanni Bajo"
<no***@sorry.com> might have written:
I have a generic solution for this (never submitted to the cookbook... should
I?)


This is by Andrew Durdin:

http://aspn.activestate.com/ASPN/Coo.../Recipe/303439

This is by me:

http://py.vaults.ca/apyllo.py/514463...4789.385587050
--
TZOTZIOY, I speak England very best.
"Dear Paul,
please stop spamming us."
The Corinthians
Jan 26 '06 #7

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

1 post views Thread by John Hunter | last post: by
1 post views Thread by fedor | last post: by
23 posts views Thread by Bob Hollness | last post: by
4 posts views Thread by bullockbefriending bard | last post: by
9 posts views Thread by Mohitz | last post: by
2 posts views Thread by satyanarayan sahoo | last post: by
5 posts views Thread by Cromulent | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.