Python成语返回第一项或None

我确信有一个简单的方法来做到这一点,只是没有发生在我身上。

我打电话了一堆返回列表的方法。 该列表可能是空的。 如果列表非空,我想返回第一个项目; 否则,我想返回None。 此代码工作:

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

在我看来,这样做应该有一个简单的一行成语,但是对于我来说,我想不起来。 在那儿?

编辑:

我在这里寻找单行expression式的原因并不是我喜欢难以置信的简洁代码,而是因为我不得不写很多这样的代码:

 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 

我想做的事情当然可以用一个函数来完成(可能会):

 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 

我发布了这个问题,因为我常常被Python中的简单expression式所惊讶,我认为编写一个函数是一件很愚蠢的事,如果有一个简单的expression式可以做到这一点。 但看到这些答案,似乎是一个function简单的解决scheme。

Python 2.6+

 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: ... 

另一种select是内联上述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 

为了避免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 

最好的办法是这样的:

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

你也可以用一行来完成,但程序员读起来要困难得多:

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

这应该工作。

顺便说一句,我没有使用variableslist ,因为这会覆盖内置的list()函数。

编辑:我有一个稍微简单,但在这里错误的版本。

最常用的Python方法是在迭代器上使用next(),因为列表是可迭代的 。 就像@JFSebastian在2011年12月13日发表的评论中所说的那样。

next(iter(the_list), None)如果the_list为空,则返回None。 看下一个()Python 2.6+

或者如果你确定the_list不是空的:

iter(the_list).next()请参阅iterator.next()Python 2.2+

OP的解决scheme几乎就在那里,只有几件事情使它变得更加Pythonic。

首先,没有必要得到列表的长度。 Python中的空列表在if检查中评估为False。 只是简单地说

 if list: 

此外,分配与保留字重叠的variables是一个非常糟糕的想法。 “list”是Python中的保留字。

所以让我们改变

 some_list = get_list() if some_list: 

这里有很多解决scheme非常重要, 所有的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风味。

如果你发现自己试图从列表理解中摘下第一个东西(或无),你可以切换到一个生成器来执行它,如:

 next((x for x in blah if cond), None) 

Pro:如果blah不可索引,则工作。Con:这是不熟悉的语法。 虽然在ipython中进行黑客入侵和过滤是非常有用的。

 for item in get_list(): return item 

对于这个问题,这里还有另一种可能性。

 return None if not get_list() else get_list()[0] 

好处:该方法处理get_list为None的情况,不使用try / except或assignment。 据我所知,上面的实现都不能处理这种可能性

垮台:get_list()被调用两次,相当不必要的,特别是如果列表很长和/或调用该函数时创build。

事实是,在我看来,更“Python”是提供可读的代码,而不仅仅是因为你可以做出一行代码:)我不得不承认,我多次因为不必要地压缩Python代码而感到内疚,我很感动,我可以做一个复杂的function,看起来很小:)

编辑:用户“hasen j”在下面评论,上面的条件expression式在Python 2.5中是新的,如下所述: https : //docs.python.org/whatsnew/2.5.html#pep-308 。 谢谢,哈森!

Python成语返回第一项还是无?

Pythonic的方法是最有争议的答案,当我读到这个问题时,我首先想到的是这个答案。 以下是如何使用它,首先如果可能的空列表传递给一个函数:

 def get_first(l): return l[0] if l else None 

如果列表是从get_list函数返回的:

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

其他方式表明要做到这一点,解释

for

当我开始想办法做到这一点时,我想到的第二件事就是:

 for item in get_list(): return item 

这假定函数在这里结束,如果get_list返回一个空列表,隐式返回None 。 下面的显式代码是完全等价的:

 for item in get_list(): return item return None 

if some_list

还提出了以下(我更正了不正确的variables名称),它也使用隐式None 。 这将比上面更好,因为它使用逻辑检查而不是可能不会发生的迭代。 这应该更容易理解发生的事情。 但是,如果我们为了可读性和可维护性而编写代码,我们还应该在末尾添加明确的return None

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

切片or [None]并select第零索引

这也是最受赞赏的答案:

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

切片是不必要的,并在内存中创build一个额外的单项清单。 以下应该是更高性能。 要解释, or返回第二个元素,如果第一个元素是布尔上下文中的False ,那么如果get_list返回一个空列表,那么包含在括号中的expression式将返回一个带有“None”的列表,然后将被0索引:

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

下一个使用的事实是,并返回第二个项目,如果第一个是在布尔上下文中为True ,并且因为它引用my_list两次,它不比三元expression式(技术上不是一个单行):

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

next

接下来我们有如下巧妙的内build使用方法

 return next(iter(get_list()), None) 

为了解释, iter使用.next方法返回一个迭代器。 (Python 3中的.__next__ )然后内置next调用.next方法,如果迭代器耗尽,则返回默认值None

多余的三元expression式( a if b else c )并回转

下面是提出的,但反过来是可取的,因为逻辑通常更好地理解在积极的而不是消极的。 由于get_list被调用两次,除非结果以某种方式被记忆,否则这将performance不佳:

 return None if not get_list() else get_list()[0] 

更好的反面:

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

更好的get_list是使用一个局部variables,这样get_list只被调用一次,而且你首先讨论了推荐的Pythonic解决scheme:

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

坦率地说,我认为没有更好的习惯用语:你的语言清晰简洁 – 不需要任何“更好”的东西。 也许,但这真的是一个品味的问题,你可以改变, if len(list) > 0: if list: – 一个空列表将始终评价为False。

在相关说明中,Python 不是 Perl(不是双关语!),您不必获得最酷的代码。
实际上,我在Python中看到的最糟糕的代码也非常酷:-),完全无法维护。

顺便说一下,我在这里看到的大部分解决scheme都没有考虑到list [0]的计算结果为False(例如空string或零) – 在这种情况下,它们都返回None,而不是正确的元素。

出于好奇,我跑了两个解决scheme的时间。 使用return语句提前结束for循环的解决scheme,在我的机器上使用Python 2.5.1的成本稍高,我怀疑这与设置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 

这是我得到的时机:

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

这个怎么样:

(my_list and my_list[0]) or None

注意:对于对象列表,这应该可以正常工作,但是如果数字或string列表根据下面的注释,它可能会返回错误的答案。

 try: return a[0] except IndexError: return None 
 def head(iterable): try: return iter(iterable).next() except StopIteration: return None print head(xrange(42, 1000) # 42 print head([]) # None 

顺便说一句:我会重新将您的一般程序stream程如下所示:

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

(尽可能避免重复)

关于成语,有一个itertools配方称为nth

从itertools食谱:

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

如果你想单行,可以考虑安装一个为你实现这个配方的库,例如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通常可以为任何迭代进行缩放,而不仅仅是用于列表。

你可以使用提取方法 。 换句话说,将这些代码提取到一个你将要调用的方法中。

我不会试图压缩它,这一行似乎比详细的版本更难读。 如果你使用提取方法,这是一个class轮;)

使用和 – 或技巧:

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

那么怎么样: next(iter(get_list()), None) ? 可能不是这里最快的,但标准(从Python 2.6开始)和简洁。

可能不是最快的解决scheme,但没有人提到这个选项:

 dict(enumerate(get_list())).get(0) 

如果get_list()可以返回None您可以使用:

 dict(enumerate(get_list() or [])).get(0) 

优点:

-一条线

– 你只需调用get_list()一次

-容易明白

我的用例只是设置一个局部variables的值。

我个人发现尝试和除了风格清洁剂阅读

 items = [10, 20] try: first_item = items[0] except IndexError: first_item = None print first_item 

比切分列表。

 items = [10, 20] first_item = (items[:1] or [None, ])[0] print first_item 
 if mylist != []: print(mylist[0]) else: print(None) 

有几个人build议做这样的事情:

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

这在很多情况下都是有效的,但是只有当列表[0]不等于0,False或者一个空string时,它才会起作用。 如果list [0]是0,False或空string,则该方法将错误地返回None。

我在自己的代码中创build了这个bug太多了!

不是与C式三元运算符相当的惯用python

 cond and true_expr or false_expr 

即。

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