Pythonic在for循环中使用'else'的方法

Lak*_*sad 13 python for-loop

我几乎没有注意到在for循环中使用else的python程序.

我最近使用它在退出时根据循环变量条件执行操作; 因为它在范围内.

在for循环中使用else的pythonic方法是什么?有没有值得注意的用例?

而且,是的.我不喜欢使用break语句.我宁愿将循环条件设置为复杂的.如果我不喜欢使用break语句,我能从中获得任何好处吗?

值得注意的是,自语言开始以来,for循环有一个else,这是第一个版本.

Tho*_*day 15

有什么比PyPy更pythonic?

看一下我在c​​types_configure/configure.py第284行开始发现的内容:

    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'],))
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)

在pypy/annotation/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
Run Code Online (Sandbox Code Playgroud)

pypy/annotation/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
Run Code Online (Sandbox Code Playgroud)

稍后在同一个文件中,从第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)
Run Code Online (Sandbox Code Playgroud)


Ben*_*kin 10

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

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 divisible by", divisor)
else:
    print(n, "is prime")
Run Code Online (Sandbox Code Playgroud)

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

for divisor in range(2, n):
    if n % divisor == 0:
        print(n, "is divisible by", divisor)
        break
else:
    print(n, "is prime")
Run Code Online (Sandbox Code Playgroud)

请注意,当您确实找到除数时,代码已经有一个自然的执行位置 - 就在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")
Run Code Online (Sandbox Code Playgroud)

注意优雅!代码1:1就是你想说的!

[这与带有 a 的循环具有相似的效率break,因为该any()函数是短路的,仅运行生成器表达式直到它产生True。]

但这不会给你实际的除数,因为any()总是返回精确的Trueor Falseelse:当您需要(A)访问“找到”的当前值(B)“找到”与“未找到”情况的单独代码路径时,循环很难被击败。


Ste*_*röm 6

如果你有一个for循环,你真的没有任何条件声明.因此,如果您想中止,那么休息是您的选择,然后可以完美地处理您不满意的情况.

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


Fer*_*yer 5

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

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

for x in range(10):
  pass
print "else"
Run Code Online (Sandbox Code Playgroud)

else使用foror的唯一原因while是在循环正常终止的情况下在循环后执行某些操作,这意味着没有显式的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
Run Code Online (Sandbox Code Playgroud)

  • 但现在,我预测,您将面临到处使用它的机会的风险。 (3认同)
  • 我可能会写:“如果文件被修改(文件):send_directory_to_server();返回True”并删除else:子句.. (2认同)