I'm sure there's a simpler way of doing this that's just not occurring to me.
I'm calling a bunch of methods that return a list. The list may be empty. If the list is non-empty, I want to return the first item; otherwise, I want to return None. This code works:
my_list = get_list()
if len(my_list) > 0: return my_list[0]
return None
It seems to me that there should be a simple one-line idiom for doing this, but for the life of me I can't think of it. Is there?
Edit:
The reason that I'm looking for a one-line expression here is not that I like incredibly terse code, but because I'm having to write a lot of code like this:
x = get_first_list()
if x:
# do something with x[0]
# inevitably forget the [0] part, and have a bug to fix
y = get_second_list()
if y:
# do something with y[0]
# inevitably forget the [0] part AGAIN, and have another bug to fix
What I'd like to be doing can certainly be accomplished with a function (and probably will be):
def first_item(list_or_none):
if list_or_none: return list_or_none[0]
x = first_item(get_first_list())
if x:
# do something with x
y = first_item(get_second_list())
if y:
# do something with y
I posted the question because I'm frequently surprised by what simple expressions in Python can do, and I thought that writing a function was a silly thing to do if there was a simple expression could do the trick. But seeing these answers, it seems like a function is the simple solution.
You could use Extract Method. In other words extract that code into a method which you'd then call.
I wouldn't try to compress it much more, the one liners seem harder to read than the verbose version. And if you use Extract Method, it's a one liner ;)
And what about:
next(iter(get_list()), None)
? Might not be the fastest one here, but is standard (starting from Python 2.6) and succinct.Out of curiosity, I ran timings on two of the solutions. The solution which uses a return statement to prematurely end a for loop is slightly more costly on my machine with Python 2.5.1, I suspect this has to do with setting up the iterable.
These are the timings I got:
The most Pythonic approach is what the most upvoted answer demonstrated, and it was the first thing to come to my mind when I read the question. Here's how to use it, first if the possibly empty list is passed into a function:
And if the list is returned from a
get_list
function:Other ways demonstrated to do this here, with explanations
for
When I began trying to think of clever ways to do this, this is the second thing I thought of:
This presumes the function ends here, implicitly returning
None
ifget_list
returns an empty list. The below explicit code is exactly equivalent:if some_list
The following was also proposed (I corrected the incorrect variable name) which also uses the implicit
None
. This would be preferable to the above, as it uses the logical check instead of an iteration that may not happen. This should be easier to understand immediately what is happening. But if we're writing for readability and maintainability, we should also add the explicitreturn None
at the end:slice
or [None]
and select zeroth indexThis one is also in the most up-voted answer:
The slice is unnecessary, and creates an extra one-item list in memory. The following should be more performant. To explain,
or
returns the second element if the first isFalse
in a boolean context, so ifget_list
returns an empty list, the expression contained in the parentheses will return a list with 'None', which will then be accessed by the0
index:The next one uses the fact that and returns the second item if the first is
True
in a boolean context, and since it references my_list twice, it is no better than the ternary expression (and technically not a one-liner):next
Then we have the following clever use of the builtin
next
anditer
To explain,
iter
returns an iterator with a.next
method. (.__next__
in Python 3.) Then the builtinnext
calls that.next
method, and if the iterator is exhausted, returns the default we give,None
.redundant ternary expression (
a if b else c
) and circling backThe below was proposed, but the inverse would be preferable, as logic is usually better understood in the positive instead of the negative. Since
get_list
is called twice, unless the result is memoized in some way, this would perform poorly:The better inverse:
Even better, use a local variable so that
get_list
is only called one time, and you have the recommended Pythonic solution first discussed:Regarding idioms, there is an itertools recipe called
nth
.From itertools recipes:
If you want one-liners, consider installing a library that implements this recipe for you, e.g.
more_itertools
:Another tool is available that only returns the first item, called
more_itertools.first
.These itertools scale generically for any iterable, not only for lists.