更具Python风格的有条件边界循环表达方法?

5 投票
6 回答
906 浏览
提问于 2025-04-15 22:01

我有一个循环,它想要一直执行,直到耗尽或者达到用户指定的限制。我写的代码看起来不太好,但我找不到更优雅的写法;有没有更好的方法呢?

def ello_bruce(limit=None):
    for i in xrange(10**5):
        if predicate(i):
            if not limit is None:
                limit -= 1
                if limit <= 0:
                   break

def predicate(i):
    # lengthy computation
    return True

哇,这个嵌套太复杂了!一定有更好的办法。为了举个例子,这里用到了xrange,通常我会用一个长度有限但不确定的迭代器(而且有时候条件会返回假)。

6 个回答

1

我会从这个开始:

if limit is None: return

因为当limit一开始是None的时候,什么事情都不会发生(前提是迭代和计算predicate的时候没有任何副作用——如果有副作用的话,你可以直接用for i in xrange(10**5): predicate(i)来处理)。

如果limit不是None,那么你只想执行predicate中为真的计算,次数是max(limit, 1),所以可以使用itertools.isliceitertools.ifilter来实现:

import itertools as it

def ello_bruce(limit=None):
    if limit is None:
        for i in xrange(10**5): predicate(i)
    else:
        for _ in it.islice(
          it.ifilter(predicate, xrange(10**5),
          max(limit, 1)): pass
2

我建议你好好看看 itertools 这个库。用这个库的话,我觉得你可以做到类似下面这样的事情...

# From the itertools examples
def tabulate(function, start=0):
    return imap(function, count(start))
def take(n, iterable):
    return list(islice(iterable, n))

# Then something like:
def ello_bruce(limit=None):
  take(filter(tabulate(predicate)), limit)
11

也许像这样会稍微好一些:

from itertools import ifilter, islice

def ello_bruce(limit=None):
    for i in islice(ifilter(predicate, xrange(10**5)), limit):
        # do whatever you want with i here

撰写回答