在for循环中使用'else'的Python方法[duplicate]

crcmnpdw  于 2023-03-16  发布在  Python
关注(0)|答案(8)|浏览(173)

此问题在此处已有答案

Why does python use 'else' after for and while loops?(24个答案)
8个月前关闭。
我几乎从来没有注意到一个python程序在for循环中使用else。
我最近使用它在退出时根据循环变量条件执行一个操作;因为它在范围内。
在for循环中使用else的Python方法是什么?有什么值得注意的用例吗?
而且,是的。我不喜欢使用break语句。我宁愿把循环条件设置为复杂的。如果我不喜欢使用break语句,我能从中得到什么好处吗?
值得注意的是,自语言诞生以来,for循环就有一个else,这是有史以来的第一个版本。

webghufk

webghufk1#

还有什么能比PyPy更像Python呢?
看看我在ctypes_configure/ www.example.com中从第284行开始发现的内容configure.py:

for i in range(0, info['size'] - csize + 1, info['align']):
        if layout[i:i+csize] == [None] * csize:
            layout_addfield(layout, i, ctype, '_alignment')
            break
    else:
        raise AssertionError("unenforceable alignment %d" % (
            info['align'],))

这里,从pypy/annotation/annrpython.py(clicky)中的第425行开始

if cell.is_constant():
    return Constant(cell.const)
else:
    for v in known_variables:
        if self.bindings[v] is cell:
            return v
    else:
        raise CannotSimplify

在pypy/annotation/ www.example.com中binaryop.py,从第751行开始:

def is_((pbc1, pbc2)):
    thistype = pairtype(SomePBC, SomePBC)
    s = super(thistype, pair(pbc1, pbc2)).is_()
    if not s.is_constant():
        if not pbc1.can_be_None or not pbc2.can_be_None:
            for desc in pbc1.descriptions:
                if desc in pbc2.descriptions:
                    break
            else:
                s.const = False    # no common desc in the two sets
    return s

pypy/annotation/ www.example.com中的非一行程序classdef.py,从第176行开始:

def add_source_for_attribute(self, attr, source):
    """Adds information about a constant source for an attribute.
    """
    for cdef in self.getmro():
        if attr in cdef.attrs:
            # the Attribute() exists already for this class (or a parent)
            attrdef = cdef.attrs[attr]
            s_prev_value = attrdef.s_value
            attrdef.add_constant_source(self, source)
            # we should reflow from all the reader's position,
            # but as an optimization we try to see if the attribute
            # has really been generalized
            if attrdef.s_value != s_prev_value:
                attrdef.mutated(cdef) # reflow from all read positions
            return
    else:
        # remember the source in self.attr_sources
        sources = self.attr_sources.setdefault(attr, [])
        sources.append(source)
        # register the source in any Attribute found in subclasses,
        # to restore invariant (III)
        # NB. add_constant_source() may discover new subdefs but the
        #     right thing will happen to them because self.attr_sources
        #     was already updated
        if not source.instance_level:
            for subdef in self.getallsubdefs():
                if attr in subdef.attrs:
                    attrdef = subdef.attrs[attr]
                    s_prev_value = attrdef.s_value
                    attrdef.add_constant_source(self, source)
                    if attrdef.s_value != s_prev_value:
                        attrdef.mutated(subdef) # reflow from all read positions

在同一个文件的后面,从第307行开始,有一个例子,其中有一个启发性的注解:

def generalize_attr(self, attr, s_value=None):
    # if the attribute exists in a superclass, generalize there,
    # as imposed by invariant (I)
    for clsdef in self.getmro():
        if attr in clsdef.attrs:
            clsdef._generalize_attr(attr, s_value)
            break
    else:
        self._generalize_attr(attr, s_value)
w1jd8yoj

w1jd8yoj2#

基本上,它简化了任何使用布尔标志的循环,如下所示:

found = False                # <-- initialize boolean
for divisor in range(2, n):
    if n % divisor == 0:
        found = True         # <-- update boolean
        break  # optional, but continuing would be a waste of time

if found:                    # <-- check boolean
    print n, "is composite"
else:
    print n, "is prime"

并允许您跳过标记的管理:

for divisor in range(2, n):
    if n % divisor == 0:
        print n, "is composite"
        break
else:
    print n, "is prime"

注意,当您找到除数时,已经有了一个自然的代码执行位置-就在break之前。这里唯一的新特性是当您尝试了所有除数但没有找到任何除数时,代码执行的位置。

  • 这只在与break结合使用时才有帮助 *。如果你不能break,你仍然需要布尔值(例如,因为你在寻找最后一个匹配,或者必须并行跟踪几个条件)。

哦,顺便说一句,这对while循环同样有效。

任何/所有

如果循环的唯一目的是回答是或否,则可以使用带有生成器或生成器表达式的any()/all()函数:

if any(n % divisor == 0 
       for divisor in range(2, n)):
    print n, "is composite"
else:
    print n, "is prime"

注意优雅!代码是1:1你想说什么!
[This和break的循环一样有效,因为any()函数是短路的,只运行生成器表达式,直到生成True。较简单的Python代码往往具有较少的偷听,因此实际上可能更快。]
如果你想找到除数,真实值是没有帮助的,因为any()总是精确地返回TrueFalse

divisor = any(d for d in range(2, n) if n % d == 0)
if divisor:
    print n, "is divisible by", divisor
else:
    print n, "is prime"

此外,如果0能够以某种方式解决any()搜索中的条件,那么没有 Package 器(如[divisor])就无法工作。

syqv5f0l

syqv5f0l3#

如果你有一个for循环,你实际上没有任何条件语句,所以break是你的选择,如果你想中止,那么else可以完美地处理你不满意的情况。

for fruit in basket:
   if fruit.kind in ['Orange', 'Apple']:
       fruit.eat()
       break
else:
   print 'The basket contains no desirable fruit'
xxls0lw8

xxls0lw84#

如果不使用breakelse块对forwhile语句没有任何好处。以下两个示例是等效的:

for x in range(10):
  pass
else:
  print "else"

for x in range(10):
  pass
print "else"

elseforwhile一起使用的唯一原因是,如果循环正常终止(即没有显式break),则在循环之后执行一些操作。
经过大量思考,我终于想出了一个可能有用的例子:

def commit_changes(directory):
    for file in directory:
        if file_is_modified(file):
            break
    else:
        # No changes
        return False

    # Something has been changed
    send_directory_to_server()
    return True
vojdkbi0

vojdkbi05#

也许最好的答案来自Python官方教程:
break和continue语句,以及循环中的else子句:

  • 循环语句可以有else子句;当循环因耗尽列表(使用for)或条件变为false(使用while)而终止时,将执行该语句,但当循环由break语句终止时不会执行该语句 *
bqf10yzr

bqf10yzr6#

有人向我介绍了一个很好的习惯用法,在这个习惯用法中,可以使用带有迭代器的for/break/else方案来保存时间和LOC。手头的示例是搜索不完全限定路径的候选路径。如果您想查看原始上下文,请参阅the original question

def match(path, actual):
    path = path.strip('/').split('/')
    actual = iter(actual.strip('/').split('/'))
    for pathitem in path:
        for item in actual:
            if pathitem == item:
                break
        else:
            return False
    return True

这里使用for/else之所以如此出色,是因为它避免了混淆布尔值,如果没有else,但希望实现相同数量的短路,它可以这样写:

def match(path, actual):
    path = path.strip('/').split('/')
    actual = iter(actual.strip('/').split('/'))
    failed = True
    for pathitem in path:
        failed = True
        for item in actual:
            if pathitem == item:
                failed = False
                break
        if failed:
            break
    return not failed

我认为else的使用使它更优雅,更明显。

mgdq6dx1

mgdq6dx17#

循环的else子句的一个用例是打破嵌套循环:

while True:
    for item in iterable:
        if condition:
            break
        suite
    else:
        continue
    break

它可避免重复条件:

while not condition:
    for item in iterable:
        if condition:
            break
        suite
disbfnqx

disbfnqx8#

给你:

a = ('y','a','y')
for x in a:
  print x,
else:
  print '!'

这是给尾车的。
编辑:

# What happens if we add the ! to a list?

def side_effect(your_list):
  your_list.extend('!')
  for x in your_list:
    print x,

claimant = ['A',' ','g','u','r','u']
side_effect(claimant)
print claimant[-1]

# oh no, claimant now ends with a '!'

编辑:

a = (("this","is"),("a","contrived","example"),("of","the","caboose","idiom"))
for b in a:
  for c in b:
    print c,
    if "is" == c:
      break
  else:
    print

相关问题