如何偶尔为长时间运行的Python列表推导提供反馈

2 投票
3 回答
639 浏览
提问于 2025-04-17 14:31

如果你在Python中有一个运行时间很长的列表推导式,比如:

from itertools import combinations

print [w for w in (''.join(c) for c in combinations(words, 2)) if sorted(w) == letters]

这里的words是一个包含20万个单词的列表,而letters是一个字母的列表;有没有办法偶尔打印出到目前为止处理了多少个单词,或者以其他形式显示进度报告呢?

3 个回答

0

为了让内容更完整,这里有一个小技巧,你可以用来定期打印出你的列表推导式的状态。比如说,当你在生成只包含奇数的列表时,如果想每处理一万条数据就打印一条消息,可以这样做:

test = [x for x in range(100000)
        if x % 2 or (x % 10000 == 0 and print("Processed: " + str(x)) is None and x % 2)]

不过要注意,这其实算是一种小窍门(而且因为增加了额外的条件判断,可能并不会提高性能)。所以如果你需要定期打印信息,我建议你把循环拆开,采用更合理的方式来处理这个“报告”逻辑。

1

这是一个生成器,它可以把进度记录到日志里。

def log_every(seq, every):
    for i, x in enumerate(seq):
        if (i + 1) % every == 0:
            logging.info('Generated %d', i)
        yield x

你可以这样使用它:

for c in log_every(combinations(words, 2), 2000):
    ...
1

你需要把它转换成一个普通的循环,不要试着把一个有副作用的函数混在里面:

from itertools import combinations

result = []
count = 0
for w in (''.join(c) for c in combinations(words, 2)):
    if sorted(w) == letters:
        result.append(w)
        count += 1
        if count % 2000 == 0:
            print 'Progress: {0} matching combinations found'.format(count)

print result

或者,如果你想记录测试过的组合,可以把计数放在if之前:

from itertools import combinations

result = []
count = 0
for w in (''.join(c) for c in combinations(words, 2)):
    count += 1
    if count % 2000 == 0:
        print 'Progress: {0} combinations scanned'.format(count)

    if sorted(w) == letters:
        result.append(w)

print result

撰写回答