

Python idiom for taking the single item from a list - cool-RR
http://blog.garlicsim.org/post/1198230058/python-idiom-for-taking-the-single-item-from-a-list

======
j_baker
Personally, I think this is a bit on the "clever" side. Plus, the error
message you get isn't as easy to understand as if you used an assert
statement. I'd probably just do something like this:

    
    
        def get_single(l):
            assert l and len(l) == 1
            return l[0]
    

Then you get the best of both worlds: readability and a concise one-liner.

~~~
jemfinch
> assert l and len(l) == 1

This is redundant: if a list's length is 1, then it's true in a boolean
context.

Also, please stop naming your lists 'l'. On a vast array of fonts, it differs
only in a few pixels from '1'. Use "L" instead :)

~~~
statictype
_This is redundant: if a list's length is 1, then it's true in a boolean
context._

In a boolean context, the list is true if the length is non-zero. This example
and the one the article is about is for the case where you _know_ the list to
have exactly one element. Not zero and not more than one.

~~~
jemfinch
You _are_ aware that asserting `len(L) == 1` excludes the possibility that
it's empty, right? You know what "redundant" means, right?

~~~
statictype
if L is None then asserting `len(L)==1` throws an exception.

The `if L and` part safeguards against that.

~~~
jemfinch
And the point that was made in the other branch of this thread is that if the
author intends to guard against None (who knows why?) then he should say,
explicitly, "if L is not None". That's what PEP8 recommends precisely to avoid
ambiguities such as these.

------
teilo
Excellent. That one belongs in any Python style guide. Though technically it's
not a style, it does lead to better readability, and reduces the propensity
for unforseen consequences.

~~~
jemfinch
The reason it's not in the Python style guide is because it's a symptom of
other problems in code. Lists are for holding multiple values of the same
type. If you know that a list will always have one and only one value, it's
not _conceptually_ a list, it's some other type that's been encoded into a
list for some reason, and you should fix that conceptual mismatch rather than
papering over the issue with a style idiom.

~~~
teilo
That sounds logical enough, except for two things:

First: You are often working with someone-else's library which for various
reasons you cannot change.

Second: It is not uncommon to use a standard method that may well be able to
return multiple items, but in your use case it should only return one. Case in
point: a database call that returns the result of a query.

~~~
baddox
Django's ORM, the only Python one I've experience with, provides get() for
those cases.

------
jemfinch
The real solution is not to arbitrarily encode your types as lists of exactly
one item. If you find yourself passing around such lists with enough
regularity that you feel the need to develop an idiom for deconstructing them,
you're doing something wrong.

~~~
cool-RR
More often than not you are receiving a list from some function, not
constructing it manually.

As an example: Say you have a GUI widget that can contain many entries, and
you call `widget.get_entries()` which returns a list with all the entries. But
if you know there must be only one entry, you can do `(entry,) =
widget.get_entries()`.

~~~
jemfinch
Then it should make a method which returns its known, sole entry. Returning a
list of entries from a widget which will always contain only one entry is the
logical equivalent to converting a function return value to a string and then
expecting the client to convert it back from a string. That is to say, it's
necessary in a general case (e.g., a Widget super class) but should not be
exposed that way in some specific cases (e.g., your subclass wherein you know
there will always be one entry).

In reality, you shouldn't be mucking with the entries of a widget at all; you
should tell the widget what to do and it should adjust its entries as
necessary). Demeter's law and all.

~~~
j_baker
I notice a lot of "shoulds" in this comment. Unfortunately, what should be and
what is aren't always the same thing.

~~~
jemfinch
No doubt! But since we're on the subject of "how to make code like this
better" it seems appropriate to discuss what's _really_ wrong with the code,
rather than just what sort of duct tape style guidelines we can use to patch
over its flaws :)

~~~
xiongchiamiov
Very often we can't change the API (standard library or such). Should we not
change our code to address the issue as best we can?

~~~
swolchok
This is Python. Subclass it and fix the problem, unless the guts are so opaque
that your code would be littered with subclasses and you can't figure out an
elegant, general way of fixing it (unlikely).

~~~
tmsh
This is Sparta.

    
    
      class SpartanList(list):
           def foot(self):
              return self[0]
    
    
      assert l.foot()
      return l.foot()

------
zokier
I think this style has one great drawback: it requires deeper knowledge of
Python then the 'usual' thing = stuff[0].

~~~
jfager
If someone's knowledge of Python is so shallow that they can't handle tuple
unpacking, they should learn more Python. It's one of the basic foundations of
the language, and it's hardly a difficult concept.

~~~
jrockway
Isn't "there's more than one way to do it" why Python programmers hate Perl?

~~~
j_baker
"There should be one-- and preferably only one --obvious way to do it."

A couple of things:

1) The key word is _obvious_. There are oftentimes less obvious ways to do
things that may be better for whatever reason.

2) It's not really reasonable to expect that there can only be one way to do
everything.

What it really means is that (for instance) Python only allows one way to
denote where a code block begins and ends (via indentation) while Ruby allows
you to use curly brackets and begin/end. Nor does it have an unless statement
that is equivalent to "if not"

------
StavrosK
Very good idea, I support this and will use it from now on (even though I
don't like the (thing,) Python syntax very much), as it's the only way to say
that the iterable should only have one element.

~~~
tkeller
As a commenter there noted,

[thing] = stuff

works too. I think I like that even better.

~~~
StavrosK
Oh, you're very much correct. Let me benchmark that...

There doesn't appear to be any difference in speed between the two. Assigning
the result to one variable (totally different to this) is about 6% faster, so
this syntax is what I'll use, thank you!

~~~
jrockway
_Assigning the result to one variable (totally different to this) is about 6%
faster, so this syntax is what I'll use, thank you!_

On your exact machine with your exact version of Python, today.

Please don't let microbenchmarks dictate what code you write. If you need a 6%
performance gain in a microbenchmark, you've chosen the wrong language to use.
Python is about readability and maintainability, not syntax hacks to make some
benchmark slightly faster.

~~~
StavrosK
The point of the above post was to say "this is nice syntax, and it isn't ten
times slower, so it's good on that front too", not to say "use that because
it's 6% faster". I'm never going to write this in a tight loop anyway, and
even if I _did_ , I'd benchmark the entire piece of code, not just this line.

------
krosaen
[thing] = stuff

also works and is more readable IMHO.

------
rbanffy
I may not be Dutch enough, but this certainly isn't the obvious way to do it.

------
statictype
So we have

 _so if I was wrong in my original assumption that stuff has exactly one
element, Python will shout at me before this will manifest itself as a hard-
to-find bug someplace else in the program._

and then later on,

 _This method works even when stuff is a set or any other kind of collection.
stuff[0] wouldn’t work on a set because set doesn’t support access by index
number._

The second argument is basically in favor of duck-typing which is the pythonic
way of writing code, ie, not caring about the actual object but only if it
responds to the given message.

But what about the first argument? Couldn't you make the case that the
pythonic way of handling it is to only care about if the object responds to
__getitem__(0)?

Which idiom you use would depend entirely on context, wouldn't it?

~~~
masklinn
> But what about the first argument? Couldn't you make the case that the
> pythonic way of handling it is to only care about if the object responds to
> __getitem__(0)?

Mmm no? Here, what he cares about is that it's a single-element collection, he
doesn't just want the collection's first item. If he did, foo[0] would do a
better job.

So the object responding to __getitem__(0) is not a sufficient condition.

In fact, it's entirely wrong as sets do _not_ implement __getitem__. Worse,
__getitem__(0) does a very different thing than unpacking on a dict. Unpacking
is _more_ ducky than __getitem__ for this case, because it expresses the
following: the right-hand is a single-element iterable. Any iterable will work
as long as it only has a single item, it doesn't have to be a sequence, a
mapping, or even a collection (generators or callable_iterators will work just
as well)

------
Goladus
My problem is that exact situation almost never comes up. Usually, I want to
use the item in the list directly in an expression, not assign it to another
variable first. For example:

    
    
        if 1==len(lst):
            return lst[0]
        else:
            return reduce(fn, lst)
    

I don't really want to have to do:

    
    
        if 1==len(lst):
            (single,)=lst
            return single
        else:
            return reduce(fn, lst)

~~~
masklinn
That's very different than OP's piece of code: you're not trying to assert
that the iterable yields a single element, you already know it.

Furthermore, OP's assertion-unpacking will work not just on lists, but also on
dicts (will return the only key, not the only value, and the key doesn't have
to be ``0``), on sets (which don't implement __getitem__ at all), on arbitrary
collections and even on arbitrary iterables (including callable_iterator and
generators)

Also, please don't put the constant on the left-hand of a comparison in
Python, it's useless and ugly.

~~~
Goladus
I agree it's cool that it works on lists and sets and dictionary keys.
Upvoted, etc. Just noting that there are many situations where it won't
replace the [0].

Also, I don't worry about order on simple equality expressions unless someone
asks me to do it a certain way. That's a religious argument and a complete
waste of time for me.

------
agentultra
Single-element tuple unpacking?

I've never found a case where I knew there would only be one element in a
list, but I do use tuple unpacking all of the time.

Pretty cool I guess; didn't know it _wasn't_ a common idiom. Good to know.
Thanks for sharing. :)

~~~
marcinw
<http://docs.python.org/library/struct.html#struct.unpack>

"""The result is a tuple even if it contains exactly one item."""

I run into this constantly using struct.unpack(), and I find the author's
idiom to be ideal way to handle this. I will use this from now on.

------
guns
Seems he would have more fun being a Rubyist.

~~~
msbarnett
Funny, I was just thinking how much cleaner a supposedly-horrid monkey-patch
would make his example in Ruby.

    
    
      thing = some_dict[my_object.get_foobar_handler()].get_only_element()
    

self-documents the purpose of the operation and its assumption much more
legibly than the typo-esque

    
    
      (thing,) =  ...
    

in my opinion.

~~~
guns
Well, that's another way to do it.

;)

------
DougBTX
I prefer array.single(), I think it's a rare enough use-case that spelling out
what you are doing is worthwhile.

~~~
j_baker
Are you talking about another language?

1) In python, arrays and lists are two _very_ different things.

2) Neither the array module nor the array class have a single function.

~~~
DougBTX
The example came to mind via C#. I assumed that it could be added to Python
via a mixin or whatever if you wanted to do it there.

------
necubi
The same code works in ruby, though without the assertion behavior:

    
    
        > a = [0]
        > b, = a
        > b == 0
         => true

------
alrex021
There you have it folks, Python supports destructuring assignment. :-)

~~~
jerf
What's the smiley for?

    
    
        Python 2.6.5...
        Type "help", "copyright", "credits" or "license" for more information.
        >>> (a, (b, c, (d, e))) = (1, (2, 3, (4, 5)))
        >>> a, b, c, d, e
        (1, 2, 3, 4, 5)
        >>> (a, (b, c, (d, e))) = (1, (2, 3, (4, 5, 6)))
        Traceback (most recent call last):
          File "<stdin>", line 1, in <module>
        ValueError: too many values to unpack
    

It isn't quite as flexible as functional languages and it's not as idiomatic
as it is in functional languages, but it's not a hack or quirky edge-case
either.

------
torrentabuse
Proposed style guide:

When you want to get the (n+1)th item from a list, do:

item = stuff[n]

To get the first item, do:

item = stuff[0]

Unless the list has one element, then do:

(item, ) = stuff

At least you'll never be accused of consistency.

~~~
StavrosK
Not really. The first two are consistent, but the last one is "get the only
item _and assert that there is only one item to get_. If you don't care about
the assertion, use [0], as always. I like the latter, because there's added
info for the reader ("this should return a one-item iterable").

It's not really inconsistent, because you aren't performing the same operation
in the two cases.

------
yangyang
thing, = stuff works too.

~~~
c-oreills
I think the comma's a lot easier to miss compared to (thing,) though.

