Filling in a tuple from unknown size list

Discussion in 'Python' started by boblatest, Nov 27, 2009.

  1. boblatest

    boblatest Guest

    Hello all,

    (sorry for posting from Google. I currently don't have access to my
    normal nntp account.)

    Here's my question: Given a list of onknown length, I'd like to be
    able to do the following:

    (a, b, c, d, e, f) = list

    If the list has fewer items than the tuple, I'd like the remaining
    tuple elements to be set to "None". If the list is longer, I'd like
    the excess elements to be ignored.

    The code snippet below does what I want, I was just wondering if there
    was an interesting "Pythonic" way of expressing the same thing.

    Thanks,
    robert

    def iter_inf(li, n):
    for i in range(n):
    if i < len(li):
    r = li
    else:
    r = None
    i += 1
    yield r


    li = ['a', 'b', 'c']
    (a, b, c, d, e) = iter_inf(li, 5)
    print a, b, c, d, e
    boblatest, Nov 27, 2009
    #1
    1. Advertising

  2. boblatest

    Peter Otten Guest

    boblatest wrote:

    > Hello all,
    >
    > (sorry for posting from Google. I currently don't have access to my
    > normal nntp account.)
    >
    > Here's my question: Given a list of onknown length, I'd like to be
    > able to do the following:
    >
    > (a, b, c, d, e, f) = list
    >
    > If the list has fewer items than the tuple, I'd like the remaining
    > tuple elements to be set to "None". If the list is longer, I'd like
    > the excess elements to be ignored.
    >
    > The code snippet below does what I want, I was just wondering if there
    > was an interesting "Pythonic" way of expressing the same thing.
    >
    > Thanks,
    > robert
    >
    > def iter_inf(li, n):
    > for i in range(n):
    > if i < len(li):
    > r = li
    > else:
    > r = None
    > i += 1
    > yield r
    >
    >
    > li = ['a', 'b', 'c']
    > (a, b, c, d, e) = iter_inf(li, 5)
    > print a, b, c, d, e


    Here's an alternative implementation that works with arbitrary iterables:

    >>> from itertools import chain, repeat, islice
    >>> a, b, c = islice(chain("a", repeat(None)), 3)
    >>> a, b, c

    ('a', None, None)
    >>> a, b, c = islice(chain("abcde", repeat(None)), 3)
    >>> a, b, c

    ('a', 'b', 'c')

    Peter
    Peter Otten, Nov 27, 2009
    #2
    1. Advertising

  3. boblatest, 27.11.2009 13:18:
    > Here's my question: Given a list of onknown length, I'd like to be
    > able to do the following:
    >
    > (a, b, c, d, e, f) = list
    >
    > If the list has fewer items than the tuple, I'd like the remaining
    > tuple elements to be set to "None". If the list is longer, I'd like
    > the excess elements to be ignored.


    What about this:

    fillUp = [None] * 6
    (a, b, c, d, e, f) = (list + fillUp)[:6]

    Stefan
    Stefan Behnel, Nov 27, 2009
    #3
  4. boblatest

    Dave Angel Guest

    Peter Otten wrote:
    > boblatest wrote:
    >
    >
    >> Hello all,
    >>
    >> (sorry for posting from Google. I currently don't have access to my
    >> normal nntp account.)
    >>
    >> Here's my question: Given a list of onknown length, I'd like to be
    >> able to do the following:
    >>
    >> (a, b, c, d, e, f) = list
    >>
    >> If the list has fewer items than the tuple, I'd like the remaining
    >> tuple elements to be set to "None". If the list is longer, I'd like
    >> the excess elements to be ignored.
    >>
    >> The code snippet below does what I want, I was just wondering if there
    >> was an interesting "Pythonic" way of expressing the same thing.
    >>
    >> Thanks,
    >> robert
    >>
    >> def iter_inf(li, n):
    >> for i in range(n):
    >> if i < len(li):
    >> r = li
    >> else:
    >> r = None
    >> i += 1
    >> yield r
    >>
    >>
    >> li = ['a', 'b', 'c']
    >> (a, b, c, d, e) = iter_inf(li, 5)
    >> print a, b, c, d, e
    >>

    >
    > Here's an alternative implementation that works with arbitrary iterables:
    >
    >
    >>>> from itertools import chain, repeat, islice
    >>>> a, b, c = islice(chain("a", repeat(None)), 3)
    >>>> a, b, c
    >>>>

    > ('a', None, None)
    >
    >>>> a, b, c = islice(chain("abcde", repeat(None)), 3)
    >>>> a, b, c
    >>>>

    > ('a', 'b', 'c')
    >
    > Peter
    >
    >
    >

    Python 3.x has some extension to the way tuple unpacking works, and may
    solve this problem (or half of it). I'm too lazy this morning to look
    it up.

    In Python 2.x I can't see any better way than Peter's elegant solution.
    I would originally have done the chain and repeat, but followed it by
    [:3] slice notation. I suspect that building an actual list would be
    cheap enough, but I like the islice better.

    DaveA
    Dave Angel, Nov 27, 2009
    #4
  5. boblatest

    Jon Clements Guest

    On 27 Nov, 12:18, boblatest <> wrote:
    > Hello all,
    >
    > (sorry for posting from Google. I currently don't have access to my
    > normal nntp account.)
    >
    > Here's my question: Given a list of onknown length, I'd like to be
    > able to do the following:
    >
    > (a, b, c, d, e, f) = list
    >
    > If the list has fewer items than the tuple, I'd like the remaining
    > tuple elements to be set to "None". If the list is longer, I'd like
    > the excess elements to be ignored.
    >
    > The code snippet below does what I want, I was just wondering if there
    > was an interesting "Pythonic" way of expressing the same thing.
    >
    > Thanks,
    > robert
    >
    > def iter_inf(li, n):
    >     for i in range(n):
    >         if i < len(li):
    >             r = li
    >         else:
    >             r = None
    >         i += 1
    >         yield r
    >
    > li = ['a', 'b', 'c']
    > (a, b, c, d, e) =  iter_inf(li, 5)
    > print a, b, c, d, e


    An alternative to Peter's itertools implementation is this
    monstrosity...

    import re

    class name_elements:
    def __init__(self, iterable, *names):
    self.__names = set(names)
    if len(self.__names) != len(names):
    raise ValueError('names must be unique')
    for it, name in zip(iterable, names):
    if not re.match('[a-zA-Z][a-zA-Z0-9_]*', name):
    raise ValueError("name '%s' is not valid" % name)
    setattr(self, name, it)
    def __getattr__(self, item):
    if item not in self.__names:
    raise ValueError("name '%s' not present" % item)
    return self.__dict__.get(item, None)

    >>> res = name_elements(['a', 'b', 'c'], 'a', 'b', 'c', 'd', 'e')
    >>> print res.a, res.b, res.c, res.d, res.e

    a b c None None
    >>> print res.f

    Traceback (most recent call last):
    File "<pyshell#23>", line 1, in <module>
    print res.f
    File "/home/jon/rubbish.py", line 10, in __getattr__
    raise AttributeError("name '%s' not present" % item)
    AttributeError: name 'f' not present

    It removes the need to know the number being unpacked (I can see this
    being overlooked) and the variable names could come from a list
    instead of being named in code. Asking for a name that doesn't exist
    is an exception, while all other values default to None.

    However, it's not totally identical to unpacking... (and most likely
    slower)

    I s'pose namedtuple could also be abused in a similar fashion.

    Or, if you don't mind []'ing:
    >>> dd = defaultdict(lambda: None)
    >>> dd.update(zip(['a', 'b', 'c'], range(5)))
    >>> print dd['a'], dd['c'], dd['blah']

    0 2 None

    Is it obvious I'm trying to avoid doing proper work!?

    Cheers,
    Jon.
    Jon Clements, Nov 27, 2009
    #5
  6. On Fri, 27 Nov 2009 04:18:08 -0800, boblatest wrote:

    > Here's my question: Given a list of onknown length, I'd like to be able
    > to do the following:
    >
    > (a, b, c, d, e, f) = list
    >
    > If the list has fewer items than the tuple, I'd like the remaining tuple
    > elements to be set to "None". If the list is longer, I'd like the excess
    > elements to be ignored.


    I'd call that a code-smell. If I saw that in code, I'd think long and
    hard about why it was there and if I could eliminate the names a...f and
    just work directly with the list.

    But if you really do need it, I think the simplest and best way is to use
    the technique Stefan suggested:

    a, b, c, d, e, f = (list + [None]*6)[:6]

    provided list is short. If you fear that list might be huge and copying
    it will be prohibitively expensive:

    a, b, c, d, e, f = (list[:6] + [None]*6)[:6]



    --
    Steven
    Steven D'Aprano, Nov 27, 2009
    #6
  7. boblatest

    Mel Guest

    Steven D'Aprano wrote:
    > On Fri, 27 Nov 2009 04:18:08 -0800, boblatest wrote:
    >> Here's my question: Given a list of onknown length, I'd like to be able
    >> to do the following:
    >>
    >> (a, b, c, d, e, f) = list
    >>
    >> If the list has fewer items than the tuple, I'd like the remaining tuple
    >> elements to be set to "None". If the list is longer, I'd like the excess
    >> elements to be ignored.


    > I'd call that a code-smell. If I saw that in code, I'd think long and
    > hard about why it was there and if I could eliminate the names a...f and
    > just work directly with the list.


    It's a common enough thing at the boundaries of your program, letting user
    input in through the gates, as it were. Deeper in, I agree; that stuff
    should have been dealt with at the gates.

    Mel.
    Mel, Nov 27, 2009
    #7
  8. Mel, 27.11.2009 18:47:
    > Steven D'Aprano wrote:
    >> On Fri, 27 Nov 2009 04:18:08 -0800, boblatest wrote:
    >>> Here's my question: Given a list of onknown length, I'd like to be able
    >>> to do the following:
    >>>
    >>> (a, b, c, d, e, f) = list
    >>>
    >>> If the list has fewer items than the tuple, I'd like the remaining tuple
    >>> elements to be set to "None". If the list is longer, I'd like the excess
    >>> elements to be ignored.

    >
    >> I'd call that a code-smell. If I saw that in code, I'd think long and
    >> hard about why it was there and if I could eliminate the names a...f and
    >> just work directly with the list.

    >
    > It's a common enough thing at the boundaries of your program, letting user
    > input in through the gates, as it were. Deeper in, I agree; that stuff
    > should have been dealt with at the gates.


    But that may have a code smell on it, too. In most cases, when users
    provide excessive arguments that the program would ignore, that's best
    treated as an error.

    Stefan
    Stefan Behnel, Nov 27, 2009
    #8
  9. boblatest

    John Machin Guest

    On Nov 27, 11:18 pm, boblatest <> wrote:
    > Hello all,
    >
    > (sorry for posting from Google. I currently don't have access to my
    > normal nntp account.)
    >
    > Here's my question: Given a list of onknown length, I'd like to be
    > able to do the following:
    >
    > (a, b, c, d, e, f) = list
    >
    > If the list has fewer items than the tuple, I'd like the remaining
    > tuple elements to be set to "None". If the list is longer, I'd like
    > the excess elements to be ignored.


    WRONG -- sweeping excess input under the carpet is a nasssssty perlish
    trick.
    John Machin, Nov 28, 2009
    #9
  10. boblatest

    Ned Deily Guest

    In article
    <>,
    inhahe <> wrote:
    > maybe that thing in python 3 that someone mentioned is the answer, but
    > otherwise i always think Python should admit something like this:
    >
    > a, b, c, *d = list
    >
    > i.e. if list were [1,2,3,4,5], you'd get a=1, b=2, c=3, d=[4, 5]


    Extended iterable unpacking (http://www.python.org/dev/peps/pep-3132/)
    is implemented in python 3.

    $ python3
    Python 3.1.1 (r311:74543, Aug 24 2009, 18:44:04)
    [GCC 4.0.1 (Apple Inc. build 5493)] on darwin
    Type "help", "copyright", "credits" or "license" for more information.
    >>> a, b, c, *d = [1,2,3,4,5]
    >>> d

    [4, 5]

    --
    Ned Deily,
    Ned Deily, Nov 29, 2009
    #10
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Michal Mikolajczyk
    Replies:
    1
    Views:
    807
    Larry Bates
    Apr 20, 2004
  2. Davy
    Replies:
    3
    Views:
    1,889
    Wildemar Wildenburger
    Nov 7, 2007
  3. Jeff Nyman
    Replies:
    8
    Views:
    386
    Terry Reedy
    Jun 5, 2008
  4. Mohsen Pahlevanzadeh
    Replies:
    0
    Views:
    116
    Mohsen Pahlevanzadeh
    Sep 9, 2013
  5. MRAB
    Replies:
    0
    Views:
    115
Loading...

Share This Page