【问题标题】:Python: loop in elif conditionPython:在 elif 条件下循环
【发布时间】:2015-04-01 07:55:46
【问题描述】:

我正在运行 Python 3。

是否可以在elif 的条件中放置一个循环?这是我想要实现的基本想法。列表中的项目数不是恒定的。

if some_condition:
    do this
elif [ x.method() for x in list ]:
    do this to x
else:
    do something else

现在,我想到了:

if some_condition:
    do this
for x in list:
    if x.method():
        do this to x
        break

但我试图避免运行所有 if 语句,其中有很多东西在发生。我想把它放在elif 部分而不是else 中。

编辑/更多说明:

看来我需要的是any( x.method() for x in list ),但还需要引用x,这样如果条件为真,我就可以使用x

这是我试图再次理解的整个概念:

if condition:
    do this
elif list[0].method():
    do this to list[0]
elif list[1].method():
    do this to list[1]
...
elif list[n].method():
    do this to list[n]
else:
    do this

其中method() 是一些返回TrueFalse 的方法,n 是列表的大小而不是常量。

【问题讨论】:

  • 您能否提供一个具体示例来说明您正在尝试做什么? list的内容是什么? some_condition 是什么? do this 是什么? x.method() 是什么? do this to x 是什么? do something else 是什么?您希望看到的具体输出是什么?
  • @Kevin 我添加了对概念的另一个澄清,我猜可能是迄今为止最清晰的。

标签: python if-statement python-3.x


【解决方案1】:

我不认为你想要的——完全在elif 中——是可能的。您必须评估列表中是否存在any 这样的值,然后将其绑定到x 条件中。据我所知,这在 Python 的语法中是不可能的。 You can not do an assignment in the condition,虽然列表解析中的循环变量可以“泄漏”到外部范围,但对于生成器也是如此。

>>> if any(x for x in range(10) if x >= 5):
...     print x
NameError: name 'x' is not defined
>>> if any([x for x in range(10) if x >= 5]):
...     print x
9

在第二种情况(列表)中,我们有一个对x的引用,但它是整个列表中的最后一个值,而在第一种情况(生成器)中,x根本无法解析。


相反,这是另一个变体,使用生成器表达式将forif 组合在一起,并将else 添加到for 以枚举最终的else 子句。

if some_condition:
    print "do this"
else:
    for x in (x for x in lst if foo(x)):
        print "do this to", x
        break
    else:
        print "do something else"

【讨论】:

  • 如果你看一下我添加到问题中的最后一个澄清(我认为这是迄今为止最清楚的),你会说这是不可能的吗?但是感谢for ... else,我完全忘记了那个(自然)。它已经足够接近我的需要了。
  • @tobias_k 只是一个更新,我在 python 3.6 中尝试过第二种情况,它不起作用
  • @BhargavKatkam 是的,Python 3 中修复了“从列表理解中泄漏”的问题。但是请注意,它在 Python 2 中也没有“工作”,因为x 将具有列表中的最后一个值,该值在应用 any 之前完全评估。
【解决方案2】:

我现在明白了。执行更新后的编辑所说的 Pythonic 方法是创建一个 for 循环并在找到第一个项目并对其采取行动后中断,并使用循环的几乎未知和未使用的“else”。

由于“for / else”这个成语很少使用,您需要添加评论,以供以后的读者阅读。

if some_test:
    first_action()
else:
    for item in list:
        if item.method():
            do_this(item)
            break   # process no more of list
    else:   # for-else only entered if no break from the list!
        final_action()

阅读loop elses in the Python Tutorial

【讨论】:

  • 非常正确,这就是已经建议的内容。我确实完全忘记了那个。
【解决方案3】:
if [ x.method() for x in list ]:

你问,有可能吗?是的。不过,它有什么作用?可能不是你想要的。

对于list中的项目数,它会在结果列表中编造一个值。对于列表值,只有长度为零的列表为 False。 [False, False, False] 为 True,因此将执行条件主体。

如果 x.method() 应该影响以下条件决策,您可能正在寻找 all()any() .

if all(x.method() for x in list):   # will require that every *x.method* call return truth.

同样,你可能想要

if any(x.method() for x in list):   # only one required. May not do every .method if it can stop early. Beware side-effects.

【讨论】:

  • 这并没有给你一个x的引用,所以你基本上必须再做一遍才能找到正确的x
  • 是的,我想要的是 any(),但要引用 x。
【解决方案4】:

不可能完全按照你的意愿去做,但你可以用列表推导做类似的事情:

if some_condition:
    do this
else:
    res = [x for x in list if x.method()]
    if res:
        do something to res[0]
    else:
        do something else

要避免对每个值都执行x.method(),您还可以使用itertools.dropwhile。以下方法将继续检查x.method(),直到找到一个为真,然后停止并仅返回x 的值。如果它没有找到任何真实的,它会做其他事情。

from itertools import dropwhile
if some_condition:
    do this
else:
    try:
        res = next(dropwhile(lambda x: not x.method(), x))
        do something to res
    except StopIteration:
        do something else

【讨论】:

  • 这将对所有x执行x.method
  • 问题提出的语法也会如此,如果它有效的话。
  • 但是如果您阅读问题并检查示例,您会发现 OP 不想在第一次匹配后为每个 xbreaks 执行它。
  • 我不清楚,但无论如何我添加了一个没有这个问题的变体。
  • 我也想过try/except hack,但你不需要dropwhile。就做next(x for x in list if x.method())
【解决方案5】:

只要您不需要在 elif 块之外引用 x ,它就可以工作。这感觉最接近您要求的语法,但我仍然可能会选择 Kevin 或 Tobias 的答案,因为它们更明确和可读。

 def check_and_do(x):
    b = x.method()
    if b:
        do this to x
    return b

if condition:
    do this
elif any(check_and_do(x) for x in list):
    pass  # Already did this to x in check_and_do
else:
    do something else

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-11-25
    • 2020-07-15
    • 2020-12-06
    • 2020-11-14
    • 1970-01-01
    • 2011-05-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多