我调用了一堆返回列表的方法。列表可能是空的。如果列表非空,我想返回第一项;否则,我想返回None。这段代码工作:
def main():
my_list = get_list()
if len(my_list) > 0:
return my_list[0]
return None
但是,在我看来,应该有一个简单的一行习语来做这件事。是吗?
我调用了一堆返回列表的方法。列表可能是空的。如果列表非空,我想返回第一项;否则,我想返回None。这段代码工作:
def main():
my_list = get_list()
if len(my_list) > 0:
return my_list[0]
return None
但是,在我看来,应该有一个简单的一行习语来做这件事。是吗?
当前回答
这个怎么样:
(my_list and my_list[0])或None
注意:这应该适用于对象列表,但它可能会返回错误的答案,在数字或字符串列表的情况下,每个下面的注释。
其他回答
最好的方法是:
a = get_list()
return a[0] if a else None
你也可以在一行中完成,但这对程序员来说很难读懂:
return (get_list()[:1] 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.
OP的解决方案已经差不多了,只是有几件事让它更python化。
首先,不需要知道列表的长度。Python中的空列表在if检查中求值为False。只要简单地说
if list:
此外,赋值给与保留字重叠的变量是一个非常糟糕的主意。list是Python中的保留字。
我们把它改成
some_list = get_list()
if some_list:
这里很多解决方案忽略的一个非常重要的一点是,所有Python函数/方法默认返回None。试试下面的方法。
def does_nothing():
pass
foo = does_nothing()
print foo
除非你需要返回None来提前终止一个函数,否则没有必要显式地返回None。非常简洁,只要返回第一个条目,如果它存在的话。
some_list = get_list()
if some_list:
return list[0]
最后,也许这是隐含的,但只是显式的(因为显式比隐式好),你不应该让你的函数从另一个函数获取列表;把它作为参数传入。最后的结果是
def get_first_item(some_list):
if some_list:
return list[0]
my_list = get_list()
first_item = get_first_item(my_list)
正如我所说的,OP几乎已经完成了,只需稍加修改就可以获得您正在寻找的Python风格。
Python 2 + 6。
next(iter(your_list), None)
如果your_list可以为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
例子:
x = get_first(get_first_list())
if x:
...
y = get_first(get_second_list())
if y:
...
另一个选择是内联上面的函数:
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
为了避免中断,你可以这样写:
for x in yield_first(get_first_list()):
x # process x
for y in yield_first(get_second_list()):
y # process y
地点:
def yield_first(iterable):
for item in iterable or []:
yield item
return
你可以使用提取方法。换句话说,将代码提取到一个方法中,然后调用该方法。
我不会试图进一步压缩它,一行代码似乎比冗长的版本更难阅读。如果你使用提取方法,它是一行;)