受@dominecf 的answer 的简单性启发,为了好玩,我实现了一个辅助包装函数pbiter(),可以在循环中使用它来显示任何迭代的进度。 pbiter() 使用@dominecf 对myprogress() 的实现。
不要过多评价这个答案,它只是为了在纯Python中从头开始实现进步的黑客乐趣,这个答案并不意味着在任何生产环境中使用,使用tqdm或enlighten模块在真正的进步应用。
请参阅我的另一个 answer 到同一个问题,该答案显示了如何使用 enlighten 模块来取得进展。
这个答案中的pbiter() 可以非常简单地与嵌套循环中的任何可迭代对象一起使用,如下所示:
for a in pbiter(range(12)):
for b in pbiter(generator_nums(13)):
for c in pbiter(generator_nums(7), total = 7):
time.sleep(0.03)
进度条总长度由len(it) 计算出,如果它可用于可迭代(例如range(start, stop, step) 它始终可用),或者通过提供total = ... 参数,否则进度随乘数0.1 呈指数衰减(这显示了一个很好的近似值)。在第二个循环上方的三个示例中,嵌套循环具有这种指数行为。
下面的完整代码。参见代码后的 ascii-video。
Try it online!
def myprogress(current, whole=1, n=30, bars=u'▕▏▎▍▌▋▊▉', full='▉', empty='▕'):
""" current and whole can be an element of a list being iterated, or just two numbers """
p = (whole.index(current))/len(whole)+1e-9 if type(whole)==list else current/whole+1e-9
return f"{full*int(p*n)}{bars[int(len(bars)*((p*n)%1))]}{empty*int((1-p)*n)} {p*100:>6.2f}%"
def pbiter(it, *, total = None, width = 36, _cfg = {'idx': -1, 'pbs': {}, 'lline': 0}):
try:
total = total or len(it)
except:
total = None
_cfg['idx'] += 1
idx = _cfg['idx']
pbs = _cfg['pbs']
pbs[idx] = [0, total, 0]
def Show():
line2 = ' '.join([
myprogress(e[1][0], max(e[1][0], e[1][1] or
max(1, e[1][0]) / max(.1, e[1][2])), width // len(pbs))
for e in sorted(pbs.items(), key = lambda e: e[0])
])
line = line2 + ' ' * (max(0, _cfg['lline'] - len(line2)) + 0)
print(line, end = '\r', flush = True)
_cfg['lline'] = len(line2)
try:
Show()
for e in it:
yield e
pbs[idx][0] += 1
pbs[idx][2] += (1. - pbs[idx][2]) * .1
Show()
pbs[idx][2] = 1.
Show()
finally:
del pbs[idx]
def test():
import time
def generator_nums(cnt):
for i in range(cnt):
yield i
for a in pbiter(range(12)):
for b in pbiter(generator_nums(13)):
for c in pbiter(generator_nums(7), total = 7):
time.sleep(0.03)
test()
ASCII 视频输出(另见 asciinema video page):
如果由于某种原因你没有循环并且仍然想使用我的pbiter(),那么你可以通过常规的内置next()操作来使用它,如下:
# Create 3 progress bars, they are at 0% point now
a = pbiter(range(5))
b = pbiter(range(4))
c = pbiter(range(3))
# Some lines of code later, advance progress "a"
next(a)
# And later ...
next(b)
# And later ...
next(b)
# Later ...
next(a); next(c)
# Later ...
next(c); next(b)
换句话说,您可以在任何代码位置以任何顺序手动创建和推进进度条。