Python idiom to return first item or None

Viewed 376181

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:

def main():
    my_list = get_list()
    if len(my_list) > 0:
        return my_list[0]
    return None

but it seems to me that there should be a simple one-line idiom for doing this. Is there?

24 Answers

Python 2.6+

next(iter(your_list), None)

If your_list can be None:

next(iter(your_list or []), None)

Python 2.4

def get_first(iterable, default=None):
    if iterable:
        for item in iterable:
            return item
    return default

Example:

x = get_first(get_first_list())
if x:
    ...
y = get_first(get_second_list())
if y:
    ...

Another option is to inline the above function:

for x in get_first_list() or []:
    # process x
    break # process at most one item
for y in get_second_list() or []:
    # process y
    break

To avoid break you could write:

for x in yield_first(get_first_list()):
    x # process x
for y in yield_first(get_second_list()):
    y # process y

Where:

def yield_first(iterable):
    for item in iterable or []:
        yield item
        return

The best way is this:

a = get_list()
return a[0] if a else None

You could also do it in one line, but it's much harder for the programmer to read:

return (get_list()[:1] or [None])[0]
(get_list() or [None])[0]

That should work.

BTW I didn't use the variable list, because that overwrites the builtin list() function.

Edit: I had a slightly simpler, but wrong version here earlier.

The OP's solution is nearly there, there are just a few things to make it more Pythonic.

For one, there's no need to get the length of the list. Empty lists in Python evaluate to False in an if check. Just simply say

if list:

Additionally, it's a very Bad Idea to assign to variables that overlap with reserved words. "list" is a reserved word in Python.

So let's change that to

some_list = get_list()
if some_list:

A really important point that a lot of solutions here miss is that all Python functions/methods return None by default. Try the following below.

def does_nothing():
    pass

foo = does_nothing()
print foo

Unless you need to return None to terminate a function early, it's unnecessary to explicitly return None. Quite succinctly, just return the first entry, should it exist.

some_list = get_list()
if some_list:
    return list[0]

And finally, perhaps this was implied, but just to be explicit (because explicit is better than implicit), you should not have your function get the list from another function; just pass it in as a parameter. So, the final result would be

def get_first_item(some_list): 
    if some_list:
        return list[0]

my_list = get_list()
first_item = get_first_item(my_list)

As I said, the OP was nearly there, and just a few touches give it the Python flavor you're looking for.

for item in get_list():
    return item

my_list[0] if len(my_list) else None

Frankly speaking, I do not think there is a better idiom: your is clear and terse - no need for anything "better". Maybe, but this is really a matter of taste, you could change if len(list) > 0: with if list: - an empty list will always evaluate to False.

On a related note, Python is not Perl (no pun intended!), you do not have to get the coolest code possible.
Actually, the worst code I have seen in Python, was also very cool :-) and completely unmaintainable.

By the way, most of the solution I have seen here do not take into consideration when list[0] evaluates to False (e.g. empty string, or zero) - in this case, they all return None and not the correct element.

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.

import random
import timeit

def index_first_item(some_list):
    if some_list:
        return some_list[0]


def return_first_item(some_list):
    for item in some_list:
        return item


empty_lists = []
for i in range(10000):
    empty_lists.append([])

assert empty_lists[0] is not empty_lists[1]

full_lists = []
for i in range(10000):
    full_lists.append(list([random.random() for i in range(10)]))

mixed_lists = empty_lists[:50000] + full_lists[:50000]
random.shuffle(mixed_lists)

if __name__ == '__main__':
    ENV = 'import firstitem'
    test_data = ('empty_lists', 'full_lists', 'mixed_lists')
    funcs = ('index_first_item', 'return_first_item')
    for data in test_data:
        print "%s:" % data
        for func in funcs:
            t = timeit.Timer('firstitem.%s(firstitem.%s)' % (
                func, data), ENV)
            times = t.repeat()
            avg_time = sum(times) / len(times)
            print "  %s:" % func
            for time in times:
                print "    %f seconds" % time
            print "    %f seconds avg." % avg_time

These are the timings I got:

empty_lists:
  index_first_item:
    0.748353 seconds
    0.741086 seconds
    0.741191 seconds
    0.743543 seconds avg.
  return_first_item:
    0.785511 seconds
    0.822178 seconds
    0.782846 seconds
    0.796845 seconds avg.
full_lists:
  index_first_item:
    0.762618 seconds
    0.788040 seconds
    0.786849 seconds
    0.779169 seconds avg.
  return_first_item:
    0.802735 seconds
    0.878706 seconds
    0.808781 seconds
    0.830074 seconds avg.
mixed_lists:
  index_first_item:
    0.791129 seconds
    0.743526 seconds
    0.744441 seconds
    0.759699 seconds avg.
  return_first_item:
    0.784801 seconds
    0.785146 seconds
    0.840193 seconds
    0.803380 seconds avg.

Not sure how pythonic this is but until there is a first function in the library I include this in the source:

first = lambda l, default=None: next(iter(l or []), default)

It's just one line (conforms to black) and avoids dependencies.

def head(iterable):
    try:
        return iter(iterable).next()
    except StopIteration:
        return None

print head(xrange(42, 1000)  # 42
print head([])               # None

BTW: I'd rework your general program flow into something like this:

lists = [
    ["first", "list"],
    ["second", "list"],
    ["third", "list"]
]

def do_something(element):
    if not element:
        return
    else:
        # do something
        pass

for li in lists:
    do_something(head(li))

(Avoiding repetition whenever possible)

Borrowing more_itertools.first_true code yields something decently readable:

def first_true(iterable, default=None, pred=None):
    return next(filter(pred, iterable), default)

def get_first_non_default(items_list, default=None):
    return first_true(items_list, default, pred=lambda x: x!=default)
try:
    return a[0]
except IndexError:
    return None

Using the and-or trick:

a = get_list()
return a and a[0] or None

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

Several people have suggested doing something like this:

list = get_list()
return list and list[0] or None

That works in many cases, but it will only work if list[0] is not equal to 0, False, or an empty string. If list[0] is 0, False, or an empty string, the method will incorrectly return None.

I've created this bug in my own code one too many times !

isn't the idiomatic python equivalent to C-style ternary operators

cond and true_expr or false_expr

ie.

list = get_list()
return list and list[0] or None
if mylist != []:

       print(mylist[0])

   else:

       print(None)
Related