Returning a tuple-struct

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • groups.20.thebriguy@spamgourmet.com

    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_struc t, which looks
    like a tuple but also like a struct. That is, I can do:
    [color=blue][color=green][color=darkred]
    >>> time.localtime( )[/color][/color][/color]
    (2006, 1, 18, 21, 15, 11, 2, 18, 0)[color=blue][color=green][color=darkred]
    >>> time.localtime( )[3][/color][/color][/color]
    21[color=blue][color=green][color=darkred]
    >>> time.localtime( ).tm_hour[/color][/color][/color]
    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

  • James Stroud

    #2
    Re: Returning a tuple-struct

    groups.20.thebr iguy@spamgourme t.com wrote:[color=blue]
    > 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_struc t, which looks
    > like a tuple but also like a struct. That is, I can do:
    >
    >[color=green][color=darkred]
    >>>>time.localt ime()[/color][/color]
    >
    > (2006, 1, 18, 21, 15, 11, 2, 18, 0)
    >[color=green][color=darkred]
    >>>>time.localt ime()[3][/color][/color]
    >
    > 21
    >[color=green][color=darkred]
    >>>>time.localt ime().tm_hour[/color][/color]
    >
    > 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
    >[/color]

    I think stylistically better might be

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

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

    Comment

    • Giovanni Bajo

      #3
      Re: Returning a tuple-struct

      groups.20.thebr iguy@spamgourme t.com wrote:
      [color=blue][color=green][color=darkred]
      >>>> time.localtime( )[/color][/color]
      > (2006, 1, 18, 21, 15, 11, 2, 18, 0)[color=green][color=darkred]
      >>>> time.localtime( )[3][/color][/color]
      > 21[color=green][color=darkred]
      >>>> time.localtime( ).tm_hour[/color][/color]
      > 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.[/color]


      I have a generic solution for this (never submitted to the cookbook... should
      I?)


      import operator
      def NamedTuple(*arg s, **kwargs):
      class named_tuple_cla ss(tuple):
      pass

      values = []
      idx = 0
      for arg in args:
      for name in arg[:-1]:
      setattr(named_t uple_class, name,
      property(operat or.itemgetter(i dx)))
      values.append(a rg[-1])
      idx += 1
      for name,val in kwargs.iteritem s():
      setattr(named_t uple_class, name, property(operat or.itemgetter(i dx)))
      values.append(v al)
      idx += 1

      return named_tuple_cla ss(values)



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

      [color=blue][color=green][color=darkred]
      >>> t = NamedTuple(("p" , "pos", "position", 12.4))
      >>> t[/color][/color][/color]
      (12.4,)[color=blue][color=green][color=darkred]
      >>> t.p[/color][/color][/color]
      12.4[color=blue][color=green][color=darkred]
      >>> t.pos[/color][/color][/color]
      12.4[color=blue][color=green][color=darkred]
      >>> t.position[/color][/color][/color]
      12.4


      [color=blue][color=green][color=darkred]
      >>> t = NamedTuple(("p" , "pos", 12.4), length="foo")
      >>> t[/color][/color][/color]
      (12.4, 'foo')[color=blue][color=green][color=darkred]
      >>> t.p[/color][/color][/color]
      12.4[color=blue][color=green][color=darkred]
      >>> t.pos[/color][/color][/color]
      12.4[color=blue][color=green][color=darkred]
      >>> t.length[/color][/color][/color]
      'foo'
      --
      Giovanni Bajo


      Comment

      • Tom Anderson

        #4
        Re: Returning a tuple-struct

        On Thu, 18 Jan 2006 groups.20.thebr iguy@spamgourme t.com wrote:
        [color=blue]
        > Is there a better way? Thoughts?[/color]

        I was thinking along these lines:

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

        colourNames = {"red": 0, "green": 1, "blue":2}
        plum = NamedTuple(colo urNames, (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(tupl e):
        def __init__(self, values):
        tuple.__init__( self, values)
        def __getattr__(sel f, name):
        return self[self.indices[name]]

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

        plum = ColourTuple((21 9, 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

        Comment

        • Tim Roberts

          #5
          Re: Returning a tuple-struct

          groups.20.thebr iguy@spamgourme t.com wrote:
          [color=blue]
          >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_struc t, which looks
          >like a tuple but also like a struct. That is, I can do:
          >[color=green][color=darkred]
          >>>> time.localtime( )[/color][/color]
          >(2006, 1, 18, 21, 15, 11, 2, 18, 0)[color=green][color=darkred]
          >>>> time.localtime( )[3][/color][/color]
          >21[color=green][color=darkred]
          >>>> time.localtime( ).tm_hour[/color][/color]
          >21[/color]

          Ah, but it ISN'T really a tuple:
          [color=blue][color=green][color=darkred]
          >>> import time
          >>> t = time.localtime( )
          >>> type(t)[/color][/color][/color]
          <type 'time.struct_ti me'>[color=blue][color=green][color=darkred]
          >>> str(t)[/color][/color][/color]
          '(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, timr@probo.com
          Providenza & Boekelheide, Inc.

          Comment

          • James Stroud

            #6
            Re: Returning a tuple-struct

            Tom Anderson wrote:[color=blue]
            > On Thu, 18 Jan 2006 groups.20.thebr iguy@spamgourme t.com wrote:
            >[color=green]
            >> Is there a better way? Thoughts?[/color]
            >
            >
            > I was thinking along these lines:
            >
            > class NamedTuple(tupl e):
            > def __init__(self, indices, values):
            > "indices should be a map from name to index"
            > tuple.__init__( self, values)
            > self.indices = indices
            > def __getattr__(sel f, name):
            > return self[self.indices[name]]
            >
            > colourNames = {"red": 0, "green": 1, "blue":2}
            > plum = NamedTuple(colo urNames, (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?
            >[/color]

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

            The official home of the Python Programming Language


            James

            Comment

            • Christos Georgiou

              #7
              Re: Returning a tuple-struct

              On Thu, 19 Jan 2006 10:47:35 GMT, rumours say that "Giovanni Bajo"
              <noway@sorry.co m> might have written:
              [color=blue]
              >I have a generic solution for this (never submitted to the cookbook... should
              >I?)[/color]

              This is by Andrew Durdin:



              This is by me:


              --
              TZOTZIOY, I speak England very best.
              "Dear Paul,
              please stop spamming us."
              The Corinthians

              Comment

              Working...