我调用了一堆返回列表的方法。列表可能是空的。如果列表非空,我想返回第一项;否则,我想返回None。这段代码工作:

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

但是,在我看来,应该有一个简单的一行习语来做这件事。是吗?


当前回答

关于习语,有一个itertools食谱叫做nth。

来自itertools食谱:

def nth(iterable, n, default=None):
    "Returns the nth item or a default value"
    return next(islice(iterable, n, None), default)

如果你想要一行程序,可以考虑安装一个库来实现这个recipe,例如more_itertools:

import more_itertools as mit

mit.nth([3, 2, 1], 0)
# 3

mit.nth([], 0)                                             # default is `None`
# None

还有另一个只返回第一项的工具,叫做more_itertools.first。

mit.first([3, 2, 1])
# 3

mit.first([], default=None)
# None

这些itertools一般适用于任何可迭代对象,而不仅仅适用于列表。

其他回答

(get_list() or [None])[0]

这应该有用。

顺便说一句,我没有使用变量列表,因为那会覆盖内置列表()函数。

编辑:我之前有一个稍微简单,但错误的版本。

出于好奇,我对其中两个解决方案进行了计时。使用return语句提前结束for循环的解决方案在我的机器上使用Python 2.5.1的代价略高,我怀疑这与设置可迭代对象有关。

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

以下是我得到的时间:

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.

你可以使用提取方法。换句话说,将代码提取到一个方法中,然后调用该方法。

我不会试图进一步压缩它,一行代码似乎比冗长的版本更难阅读。如果你使用提取方法,它是一行;)

my_list[0] if len(my_list) else无

最好的方法是:

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

你也可以在一行中完成,但这对程序员来说很难读懂:

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