for循环中的复合条件

时间:2016-11-14 16:17:59

标签: python for-loop syntax generator list-comprehension

Python在列表推导中允许“if”条件,例如:

[l for l in lines if l.startswith('example')]

常规“for”循环中缺少此功能,因此没有:

for line in lines if line.startswith('example'):
    statements

需要评估循环中的条件:

for line in lines:
    if line.startswith('example'):
        statements

或嵌入生成器表达式,如:

for line in [l for l in lines if l.startswith('example')]:
    statements

我的理解是否正确?是否有比上面列出的方法更好或更pythonic的方式来实现在for循环中添加条件的相同结果?

请注意选择“行”作为示例,任何集合或生成器都可以在那里。

4 个答案:

答案 0 :(得分:2)

其他答案和评论提出了一些不错的想法,但我认为this recent discussion on Python-ideasits continuation是这个问题的最佳答案。

总结一下:过去已经讨论过这个想法,考虑到以下因素,这些好处似乎不足以激发语法变化:

  • 语言复杂性增加及对学习曲线的影响

  • 所有实施中的技术变更:CPython,Jython,Pypy ..

  • 极端使用synthax可能导致的奇怪情况

人们似乎高度考虑的一点是避免使Perl相似的复杂性损害可维护性。

This messagethis one很好地总结了可能的替代方案(几乎已经在本页中出现)到for循环中的复合if语句:

# nested if
for l in lines:
    if l.startswith('example'):
        body

# continue, to put an accent on exceptional case
for l in lines:
    if not l.startswith('example'):
        continue
    body

# hacky way of generator expression
# (better than comprehension as does not store a list)
for l in (l for l in lines if l.startswith('example')):
    body()

# and its named version
def gen(lines):
    return (l for l in lines if l.startswith('example'))
for line in gen(lines):
    body

# functional style
for line in filter(lambda l: l.startswith('example'), lines):
    body()

答案 1 :(得分:1)

也许不是Pythonic,但你可以filter这些线。

for line in filter(lambda l: l.startswith('example'), lines):
    print(line)

你可以定义自己的过滤功能,当然,如果这个lambda困扰你,或者你想要更复杂的过滤。

def my_filter(line):
    return line.startswith('example') or line.startswith('sample')

for line in filter(my_filter, lines):
    print(line)

我会说在循环中具有条件是更好的,因为当你迭代这些行时你没有在内存中维护“过滤”列表。

所以,那只是

for line in file:
    if not my_filter(line):
        continue
    # statements

答案 2 :(得分:0)

并不是缺少这个功能,除了一些特殊情况外,我想不出有什么方法可以做到。 (l for l in lines if l.startswith('example'))是生成器对象,l变量是该对象的本地变量。 for只能看到生成器的__next__方法返回的内容。

for非常不同,因为生成器的结果需要绑定到调用者范围内的变量。你可以写

for line in (line for line in lines if l.startswith('example')):
    foo(line)

安全,因为这两个line的范围不同。

此外,生成器不必仅返回其局部变量。它可以评估任何表达式。你会如何做到这一点?

for line in (foo(line)+'bar' for line in lines if line.startswith('example')):
    statements

假设您有一个列表列表

for l in (l[:] for l in list_of_lists if l):
    l.append('modified')

不应附加到原始列表中。

答案 3 :(得分:0)

  

是否有比上面列出的更好或更pythonic方式来实现在for循环中添加条件的相同结果?

不,没有,也不应该; 这就是为什么列表理解首先来到这里的理由。来自corresponding PEP

  

列表推导提供了一种更简洁的方式,可以在当前使用map()filter()和/或嵌套循环的情况下创建列表。

列表推导构成了嵌套forif s的替代方案;你为什么要替代替代方案?

如果您需要将iffor一起使用,则将其嵌入其中,如果您不想这样做,则使用列表推导。 Flat优于嵌套 ,但 可读性计数;允许if会导致难看的长丑线在视觉上解析。