Live data from Hacker News

Python idiom for taking the single item from a list

blog.garlicsim.org

71–80 of 97 posts

Re: Python idiom for taking the single item from a list

#71
post #36

Seems he would have more fun being a Rubyist.

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.

Re: Python idiom for taking the single item from a list

#72

Earlier quoted context omitted.

That fails for sets and other non-list iterables. It would have to be something like: def get_single(l): i = iter(l) val = i.next() try: i.next() # expected to throw exception for one-element iterable except StopIteration: return val raise AssertionError('More than one object') Eww.

You don't need to do that for a set. sets support `len()`. Also set supports `pop()`, so the code is very similar to the list one: assert s and len(s)==1 return s.pop() Or if you want to stay in the immutable land: assert s and len(s)==1 return tuple(s)[0]

Both of those still fail for other non-list iterables, like generators.

Re: Python idiom for taking the single item from a list

#73
post #64

Earlier quoted context omitted.

Yes, but with most functions there's no choice, because most of the functions in your program do something (a) complex and/or (b) specific to your program. This `get_single` function falls into neither of these categories.

Functions should not be complex. Functions should be simple, and they should be composed by other simple functions to do more complex things.

It is certainly okay for some functions to be complex. Some may rely on simpler functions, but the one you'd use can still do a complex task in general.

A function that squares a number is simple, one that computes the standard deviation is definitely more complex.

Re: Python idiom for taking the single item from a list

#74

Earlier quoted context omitted.

That fails for sets and other non-list iterables. It would have to be something like: def get_single(l): i = iter(l) val = i.next() try: i.next() # expected to throw exception for one-element iterable except StopIteration: return val raise AssertionError('More than one object') Eww.

You don't need to do that for a set. sets support `len()`. Also set supports `pop()`, so the code is very similar to the list one: assert s and len(s)==1 return s.pop() Or if you want to stay in the immutable land: assert s and len(s)==1 return tuple(s)[0]

[deleted]

Re: Python idiom for taking the single item from a list

#75
post #2

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.

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.

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.

Re: Python idiom for taking the single item from a list

#76

Earlier quoted context omitted.

Functions should not be complex. Functions should be simple, and they should be composed by other simple functions to do more complex things.

It is certainly okay for some functions to be complex. Some may rely on simpler functions, but the one you'd use can still do a complex task in general. A function that squares a number is simple, one that computes the standard deviation is definitely more complex.

> A function that squares a number is simple, one that computes the standard deviation is definitely more complex.

I'm talking about the complexity difference between this:

  def stddev(pop):
    total = 0
    count = 0
    for x in pop:
      total += x
      count += 1
    mean = total / float(count)
    variance = 0
    for x in pop:
      variance += (x - mean)**2
    return math.sqrt(variance)
    
and this:

    def stddev(pop):
      return math.sqrt(variance(pop))

    def variance(pop):
      m = mean(pop)
      return sum(square(x - m) for x in pop)

    def mean(pop):
      return sum(pop) / float(len(pop))

    def square(x):
      return x**2
The first is a (mildly) complex function. The latter are all simple functions, and the complex result is constructed by composing simple operations.

Good programmers write functions in the latter style, not the former.

Re: Python idiom for taking the single item from a list

#77
post #36

Seems he would have more fun being a Rubyist.

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.

Well, that's another way to do it.

;)

Re: Python idiom for taking the single item from a list

#78
post #68

Earlier quoted context omitted.

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?

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

This is Sparta.

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


  assert l.foot()
  return l.foot()

Re: Python idiom for taking the single item from a list

#79
post #75

Earlier quoted context omitted.

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.

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.

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

Re: Python idiom for taking the single item from a list

#80
post #47

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.

That fails for sets and other non-list iterables. It would have to be something like: def get_single(l): i = iter(l) val = i.next() try: i.next() # expected to throw exception for one-element iterable except StopIteration: return val raise AssertionError('More than one object') Eww.

Personally, I'm willing to restrict this to just lists to keep things simple. I rarely ever need a way to extract one value from a list, set, and iterable.
Post reply on HN