Python 习惯用法返回第一项或 None

2025-03-18 08:55:00
admin
原创
47
摘要:问题描述:我正在调用一堆返回列表的方法。列表可能为空。如果列表非空,我想返回第一项;否则,我想返回None。此代码有效:def main(): my_list = get_list() if len(my_list) > 0: return my_list[0] ...

问题描述:

我正在调用一堆返回列表的方法。列表可能为空。如果列表非空,我想返回第一项;否则,我想返回None。此代码有效:

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

但我觉得应该有一个简单的单行语法来做到这一点。有吗?


解决方案 1:

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

为了避免这种情况,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

解决方案 2:

最好的方法是这样的:

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

你也可以用一行来完成它,但是对于程序员来说阅读起来会困难得多:

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

解决方案 3:

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

那应该可行。


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

解决方案 4:

最符合 Python 习惯的方式是在迭代器上使用 next(),因为 list 是可迭代的。就像 @JFSebastian 在 2011 年 12 月 13 日的评论中所说的那样。

next(iter(the_list), None)如果为空,则返回 None the_list。请参阅next() Python 2.6+

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

iter(the_list).next()参见iterator.next() Python 2.2+

解决方案 5:

Python 习语返回第一个项目还是 None?

最受支持的答案所展示的是最 Python 风格的方法,这也是我读到这个问题时首先想到的方法。下面介绍如何使用它,首先,如果将可能为空的列表传递给函数:

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 中的新功能,赋值表达式

赋值表达式使用就地赋值运算符(非正式地称为海象运算符),:=它是 Python 3.8 中的新功能,允许我们就地进行检查和赋值,从而允许单行:

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

作为一名长期的 Python 用户,我感觉我们试图在一行中做太多事情 —— 我觉得更好的做法是执行假定的性能相同的操作:

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

支持这一表述的是 PEP 中 Tim Peter 的一篇文章,他建议对语言进行这种改变。他没有提到第一种表述,但基于他喜欢的其他表述,我认为他不会介意。

此处演示了其他方法,并附有说明

for

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

for item in get_list():
    return item

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

for item in get_list():
    return item
return None

if some_list

还提出了以下内容(我更正了错误的变量名),它也使用了显式。这比上面的更好,因为它使用逻辑检查而不是可能不会发生的迭代。这应该更容易立即了解正在发生的事情。但如果我们是为了可读性和可维护性而编写,我们还应该在最后None添加显式:return None

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

切片or [None]并选择第零索引

这也是获得最多赞同的答案:

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

切片是不必要的,并在内存中创建一个额外的单项列表。以下应该更高效。解释一下,or如果第一个元素False在布尔上下文中,则返回第二个元素,因此如果get_list返回一个空列表,括号中包含的表达式将返回一个带有“无”的列表,然后可以通过0索引访问该列表:

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

下一个使用这样的事实:如果第一个是True在布尔上下文中,则返回第二个项目,并且由于它引用了 my_list 两次,所以它并不比三元表达式更好(并且从技术上讲不是单行):

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

next

然后我们巧妙地使用了内置函数nextiter

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只调用一次,你就得到了首先讨论的推荐的 Pythonic 解决方案:

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

解决方案 6:

如果你发现自己试图从列表推导中挑选出第一件事(或无),你可以切换到生成器来执行此操作,如下所示:

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

优点:如果 blah 不可索引,则有效 缺点:语法不熟悉。不过,在 ipython 中破解和过滤内容时很有用。

解决方案 7:

OP 的解决方案已经差不多了,只需做一些事情就可以使它更 Pythonic。

首先,不需要获取列表的长度。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 风格。

解决方案 8:

关于习语,有一个名为的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

这些迭代工具可以通用地扩展任何可迭代对象,而不仅适用于列表。

解决方案 9:

for item in get_list():
    return item

解决方案 10:

坦白说,我认为没有更好的用法:你的用法简洁明了 - 不需要任何“更好”的东西。也许吧,但这真的是一个品味问题,你可以改变if len(list) > 0:-if list:空列表将始终计算为 False。

顺便提一下,Python不是Perl(没有双关语的意思!),你不必获得最酷的代码。

实际上,我见过的最糟糕的 Python 代码也非常酷 :-),而且完全无法维护。

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

解决方案 11:

my_list[0] if len(my_list) else None

解决方案 12:

不确定这有多么符合 Python 风格,但直到库中出现第一个函数时,我才会将其包含在源代码中:

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

它只有一行(符合黑色)并且避免了依赖性。

解决方案 13:

出于好奇,我对其中两个解决方案进行了计时。使用 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

以下是我得到的时间:

空列表:
  索引第一个项目:
    0.748353 秒
    0.741086 秒
    0.741191 秒
    平均 0.743543 秒
  返回第一个项目:
    0.785511 秒
    0.822178 秒
    0.782846 秒
    平均 0.796845 秒
完整列表:
  索引第一个项目:
    0.762618 秒
    0.788040 秒
    0.786849 秒
    平均 0.779169 秒
  返回第一个项目:
    0.802735 秒
    0.878706 秒
    0.808781 秒
    平均 0.830074 秒
混合列表:
  索引第一个项目:
    0.791129 秒
    0.743526 秒
    0.744441 秒
    平均 0.759699 秒
  返回第一个项目:
    0.784801 秒
    0.785146 秒
    0.840193 秒
    平均 0.803380 秒

解决方案 14:

try:
    return a[0]
except IndexError:
    return None

解决方案 15:

def head(iterable):
    try:
        return iter(iterable).next()
    except StopIteration:
        return None

print head(xrange(42, 1000)  # 42
print head([])               # None

顺便说一句:我会将您的一般程序流程重新设计成如下形式:

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

(尽可能避免重复)

解决方案 16:

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

解决方案 17:

下面的代码涵盖了使用 lambda 的几种场景:

l1 = [1,2,3]
l2 = []
l3 = None
first_elem = lambda x: x[0] if x else None
print(first_elem(l1))
print(first_elem(l2))
print(first_elem(l3))

解决方案 18:

如果您碰巧已经在使用funcy库....

Funcy 文档的图片

...它为 Python 提供了大量有用的、受函数式编程启发的实用程序 - 我经常发现自己这样做 - 然后,您可以利用...

来自序列相关函数部分的第一个函数:

返回序列中的第一个项目。如果序列为空,则返回 None。典型用法是从一些生成的变体中选择第一个。

...然后您可以执行以下操作:

from funcy import first

my_list = get_list()
result = first(my_list) if my_list else None

解决方案 19:

使用与或技巧:

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

解决方案 20:

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

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

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

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

优点:

-一行

-你只需打get_list()一次电话

-易于理解

解决方案 21:

我的用例只是设置局部变量的值。

我个人觉得 try 和 except 风格更简洁

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

解决方案 22:

您可以使用Extract Method。换句话说,将该代码提取到您随后要调用的方法中。

我不会尝试进一步压缩它,单行代码似乎比详细版本更难阅读。如果你使用 Extract Method,它就是一行代码 ;)

解决方案 23:

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

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

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

我在自己的代码中多次犯过此错误!

解决方案 24:

不是与 C 风格三元运算符等同的惯用 Python 代码吗?

cond and true_expr or false_expr

IE。

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

解决方案 25:

if mylist != []:

       print(mylist[0])

   else:

       print(None)
相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   2482  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1533  
  PLM(产品生命周期管理)项目对于企业优化产品研发流程、提升产品质量以及增强市场竞争力具有至关重要的意义。然而,在项目推进过程中,范围蔓延是一个常见且棘手的问题,它可能导致项目进度延迟、成本超支以及质量下降等一系列不良后果。因此,有效避免PLM项目范围蔓延成为项目成功的关键因素之一。以下将详细阐述三大管控策略,助力企业...
plm系统   0  
  PLM(产品生命周期管理)项目管理在企业产品研发与管理过程中扮演着至关重要的角色。随着市场竞争的加剧和产品复杂度的提升,PLM项目面临着诸多风险。准确量化风险优先级并采取有效措施应对,是确保项目成功的关键。五维评估矩阵作为一种有效的风险评估工具,能帮助项目管理者全面、系统地评估风险,为决策提供有力支持。五维评估矩阵概述...
免费plm软件   0  
  引言PLM(产品生命周期管理)开发流程对于企业产品的全生命周期管控至关重要。它涵盖了从产品概念设计到退役的各个阶段,直接影响着产品质量、开发周期以及企业的市场竞争力。在当今快速发展的科技环境下,客户对产品质量的要求日益提高,市场竞争也愈发激烈,这就使得优化PLM开发流程成为企业的必然选择。缺陷管理工具和六西格玛方法作为...
plm产品全生命周期管理   0  
热门文章
项目管理软件有哪些?
曾咪二维码

扫码咨询,免费领取项目管理大礼包!

云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用