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

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

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


当前回答

不确定这是如何python化的,但在库中有第一个函数之前,我将其包含在源代码中:

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

它只有一行(符合黑色),避免了依赖关系。

其他回答

返回第一项还是None?

最Pythonic的方法是得到最多赞的答案所展示的,这是我读到这个问题时想到的第一件事。下面是如何使用它,首先,如果可能为空的列表被传递到一个函数:

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

如果从get_list函数返回列表:

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

赋值表达式:Python 3.8新增功能

赋值表达式使用就地赋值操作符(非正式地称为walrus操作符),:=,Python 3.8新增的操作符,允许我们就地执行检查和赋值,允许一行代码:

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

作为一个长期的Python用户,这感觉像是我们试图在一行上做太多的事情——我觉得做假定相同的性能会是更好的风格:

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

为了支持这一提法,Tim Peter在PEP中提出了对语言的这一改变。他没有提到第一个公式,但基于他喜欢的其他公式,我认为他不会介意。

这里演示了其他方法,并给出了解释

for

当我开始试图想出聪明的方法来做到这一点时,我想到的第二件事是:

for item in get_list():
    return item

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

for item in get_list():
    return item
return None

如果some_list

下面还提出了(我更正了不正确的变量名),它也使用隐式的None。这比上面的方法更可取,因为它使用逻辑检查而不是可能不会发生的迭代。这应该更容易立即理解发生了什么。但如果我们是为了可读性和可维护性而编写,我们还应该在末尾添加显式返回None:

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

slice或[None]并选择第0个索引

这也是投票最多的答案:

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

切片是不必要的,它会在内存中创建一个额外的单项列表。下面的代码应该性能更好。为了解释,如果第一个元素在布尔上下文中为False,则返回第二个元素,因此如果get_list返回一个空列表,括号中包含的表达式将返回一个带有'None'的列表,然后由0索引访问:

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

下一个表达式使用的事实是,如果第一个在布尔上下文中为True,则返回第二项,并且由于它引用了my_list两次,因此它并不比三元表达式更好(并且技术上不是一行程序):

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

next

然后,我们有以下聪明的使用内置的next和iter

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

为了解释,iter返回一个带有.next方法的迭代器。(。__next__在Python 3中。)然后内建的next调用.next方法,如果迭代器耗尽,则返回我们给出的默认值None。

冗余三元表达式(a if b else c)并绕回来

有人提出了以下观点,但相反的观点更可取,因为逻辑通常更容易从积极的角度来理解,而不是从消极的角度。因为get_list被调用了两次,除非结果以某种方式被记住,否则执行效果会很差:

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

更好的逆:

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

更好的是,使用一个局部变量,这样get_list只被调用一次,并且您首先讨论了推荐的python解决方案:

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

坦率地说,我认为没有更好的成语了:your is clear and short -不需要什么“更好的”。也许吧,但这真的是一个品味的问题,你可以改变if len(list) > 0:与if list: -一个空列表将永远求值为False。

在相关的说明中,Python不是Perl(没有双关的意思!),您不必获得尽可能最酷的代码。 实际上,我在Python中见过的最糟糕的代码,也是非常酷的:-),而且完全无法维护。

顺便说一下,我在这里看到的大多数解决方案都不考虑list[0]计算为False(例如空字符串或零)-在这种情况下,它们都返回None而不是正确的元素。

more_itertools借款。First_true代码产生一些可读的东西:

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)

一些人建议这样做:

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

这在许多情况下都有效,但它只在列表[0]不等于0、False或空字符串时才有效。如果列表[0]为0、False或空字符串,该方法将错误地返回None。

我在自己的代码中创建了这个错误太多次了!

for item in get_list():
    return item