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