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.
> 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 :)
Python idiom for taking the single item from a list
61–70 of 97 posts
Re: Python idiom for taking the single item from a list
#62Earlier 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.
Lists use (not infrequently) logic like the following; If one element do this one element thing else do this more than one element thing
Re: Python idiom for taking the single item from a list
#63Earlier quoted context omitted.
It is a good thing if code is readable by people who only know the language a little, only know similar languages, or have not used the language for years.
It is a good thing, but it isn't the highest good. It doesn't make sense to avoid useful basic features simply because they aren't immediately obvious to a novice in the language.
Re: Python idiom for taking the single item from a list
#64Earlier quoted context omitted.
I'd avoid doing this, because people who'll read your code would have to check themselves what the `get_single` function does. Also, the performance here is probably much worse. (Although in many cases it would not matter.) But that's just my opinion, your suggestion is legitimate.
> I'd avoid doing this, because people who'll read your code would have to check themselves what the `get_single` function does. This is an argument against using functions at all. If it works against get_single, it works against all functions. That is to say, it doesn't work at all.
Re: Python idiom for taking the single item from a list
#65Personally, 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.
> 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 :)
And as was mentioned the "assert l" part is defending against l being None. I suppose I could be more explicit by saying "assert l is not None and len(l) == 1".
Re: Python idiom for taking the single item from a list
#66Earlier quoted context omitted.
> 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 :)
He's defending against None with the assert l and len(l) bit, or at least that's what I'd assume.
assert l is not None and len(l) == 1Re: Python idiom for taking the single item from a list
#67Personally, 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.
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]Re: Python idiom for taking the single item from a list
#68Earlier quoted context omitted.
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 :)
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?
Re: Python idiom for taking the single item from a list
#69Earlier quoted context omitted.
> I'd avoid doing this, because people who'll read your code would have to check themselves what the `get_single` function does. This is an argument against using functions at all. If it works against get_single, it works against all functions. That is to say, it doesn't work at all.
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.
Re: Python idiom for taking the single item from a list
#70Earlier quoted context omitted.
> 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 :)
I wouldn't name a list l in real code. It was just the first thing that popped to mind. :-) And as was mentioned the "assert l" part is defending against l being None. I suppose I could be more explicit by saying "assert l is not None and len(l) == 1".
I'm not sure why you'd defend against None anyway. Why defend against None, but not against 3.1459 or 4j or ''?