英文:
Why is tqdm progress bar not working in a for loop containing a continue statement?
问题
我正在使用Python的tqdm
库在终端显示一个进度条,当我执行一个包含for循环的Python脚本时。例如,当我执行以下代码时:
import time
from tqdm import tqdm
for i in tqdm(range(10)):
time.sleep(1)
print(' ' * 5 + str(i))
几秒后,我在终端中看到以下显示,如预期:
在这里,print
语句并不重要,只是一个计算(我只是使用print
来显示计算已完成的事实)。
现在,我添加了一个continue
语句,如下所示:
for i in tqdm(range(10)):
time.sleep(1)
if i < 5:
continue
print(' ' * 5 + str(i))
然后我得到了这个结果:
所以,我理解print
语句在5以下的每次迭代都会被跳过,但是为什么进度条没有显示? 是否tqdm
在循环结束时以某种方式添加了一个“显示进度条”的语句,因此这个顺序就像print
语句一样被跳过了?我感觉好像tqdm
仍然存储了进度条的数据(应该显示的那个进度条),所以它知道在continue
语句不再执行后从哪里继续。
无论如何,我想知道是否有一种方法可以在每次迭代中打印进度条,即使在for循环内有一个continue
语句,即使我的循环在第五次迭代之前都不会执行print(' ' * 5 + str(i))
。只是为了清楚,我期望看到类似这样的东西:
请注意,这个显示了进度条在for循环的所有迭代中都是可见的,但是直到第五次迭代之前都没有添加迭代的数字。
英文:
So I'm using the Python tqdm
library to display a progress bar in the terminal when I execute a Python script that includes a for loop.
For example, when I do this:
import time
from tqdm import tqdm
for i in tqdm(range(10)):
time.sleep(1)
print(' '*5+str(i))
I get this displayed in the terminal after a few seconds:
, as expected. Here the print
statement is not important, is just a computation (I used print
just to display the fact that the computation was done).
Now I add a continue
statement in this way:
for i in tqdm(range(10)):
time.sleep(1)
if i < 5:
continue
print(' '*5+str(i))
and I get this:
So, I understand that the print
statement is skipped for each iteration below 5, but why the progress bar is not displayed? Is tqdm
somehow adding a "display a progress bar" statement at the end of the loop and thus this order is been skipped like the print
statement? I feel like it's like if tqdm
is still storing the data of the progress bar (the one that should have been displayed), so it knows where to follow after the continue
statement is no longer executed.
In any case I would like to know if there is a way of having the progress bar printed in each iteration, even with a continue
statement inside the for loop and even if my loop won't execute print(' '*5+str(i))
until it surpasses the fifth iteration of the loop. Just to be clear, I expect to see something like this:
Notice that this displayed the progress bar through all the iterations in the for loop but didn't add the printed number of iterations until the fifth one.
答案1
得分: 2
这里有一个有点巧妙的解决方案,利用了 `bar_format`:
for i in tqdm(range(10), bar_format='\n{l_bar}{bar:20}{r_bar}'):
time.sleep(1)
if i < 5:
continue
print(' ' * 5 + str(i), end='', flush=True)
输出:
0%| | 0/10 [00:00<, ?it/s]
10%|██ | 1/10 [00:01<00:09, 1.01s/it]
20%|████ | 2/10 [00:02<00:08, 1.01s/it]
30%|██████ | 3/10 [00:03<00:07, 1.01s/it]
40%|████████ | 4/10 [00:04<00:06, 1.00s/it]
50%|██████████ | 5/10 [00:05<00:05, 1.00s/it] 5
60%|████████████ | 6/10 [00:06<00:04, 1.01s/it] 6
70%|██████████████ | 7/10 [00:07<00:03, 1.00s/it] 7
80%|████████████████ | 8/10 [00:08<00:02, 1.00s/it] 8
90%|██████████████████ | 9/10 [00:09<00:01, 1.00s/it] 9
100%|████████████████████| 10/10 [00:10<00:00, 1.00s/it]
注意 `end=''` 和 `flush=True`。
尽管它在开头产生了一个多余的空行。
附注:对于 `tqdm(range(10), ...)` 有一个快捷方式 `trange`:
from tqdm import trange
for i in trange(10, bar_format='\n{l_bar}{bar:20}{r_bar}'):
...
英文:
Here's a bit of a hacky solution utilizing bar_format
:
for i in tqdm(range(10), bar_format='\n{l_bar}{bar:20}{r_bar}'):
time.sleep(1)
if i < 5:
continue
print(' ' * 5 + str(i), end='', flush=True)
Output:
0%| | 0/10 [00:00<?, ?it/s]
10%|██ | 1/10 [00:01<00:09, 1.01s/it]
20%|████ | 2/10 [00:02<00:08, 1.01s/it]
30%|██████ | 3/10 [00:03<00:07, 1.01s/it]
40%|████████ | 4/10 [00:04<00:06, 1.00s/it]
50%|██████████ | 5/10 [00:05<00:05, 1.00s/it] 5
60%|████████████ | 6/10 [00:06<00:04, 1.01s/it] 6
70%|██████████████ | 7/10 [00:07<00:03, 1.00s/it] 7
80%|████████████████ | 8/10 [00:08<00:02, 1.00s/it] 8
90%|██████████████████ | 9/10 [00:09<00:01, 1.00s/it] 9
100%|████████████████████| 10/10 [00:10<00:00, 1.00s/it]
Note the end=''
and flush=True
.
Though it produces a redundant empty line at the start.
Sidenote: for tqdm(range(10), ...)
there's a shortcut trange
:
from tqdm import trange
for i in trange(10, bar_format='\n{l_bar}{bar:20}{r_bar}'):
...
答案2
得分: 0
`tqdm`想要覆盖先前的输出。它会产生阶梯效应,因为当`tqdm`不期望时,您的`print`会手动添加换行符。
如果您想发送一条消息,以便它不干扰进度条,您可以使用`write`,它会将您的消息放在进度条上方。
```python
iterator = tqdm(range(10))
for i in iterator:
time.sleep(0.1)
if i < 5:
continue
iterator.write(f"迭代 {i}")
迭代 5
迭代 6
迭代 7
迭代 8
迭代 9
100%|████████████████████████████████████| 10/10 [00:01<00:00, 9.20it/s]
或者,如果您想要具有在其步骤上“冻结”进度条的行为,您将不得不始终在此之后打印一些东西,尽管我并不真的推荐这样做。
for i in tqdm(range(10), ncols=60):
time.sleep(1)
if i < 5:
print()
continue
print(' '*5+str(i))
0%| | 0/10 [00:00<?, ?it/s]
10%|██▍ | 1/10 [00:00<00:00, 9.41it/s]
20%|████▊ | 2/10 [00:00<00:00, 9.27it/s]
30%|███████▏ | 3/10 [00:00<00:00, 9.23it/s]
40%|█████████▌ | 4/10 [00:00<00:00, 9.26it/s]
50%|████████████ | 5/10 [00:00<00:00, 9.18it/s] 5
60%|██████████████▍ | 6/10 [00:00<00:00, 9.21it/s] 6
70%|████████████████▊ | 7/10 [00:00<00:00, 9.21it/s] 7
80%|███████████████████▏ | 8/10 [00:00<00:00, 9.18it/s] 8
90%|█████████████████████▌ | 9/10 [00:00<00:00, 9.16it/s] 9
100%|███████████████████████| 10/10 [00:01<00:00, 9.20it/s]
英文:
tqdm
wants to overwrite its previous output. It does this staircase effect because your print
is manually adding a newline when tqdm
is not expecting that.
If you want to send out a message such that it does not interfere with the progress bar, you can use write
, which will put your message above the progress bar.
iterator = tqdm(range(10))
for i in iterator:
time.sleep(0.1)
if i < 5:
continue
iterator.write(f"iteration {i}")
iteration 5
iteration 6
iteration 7
iteration 8
iteration 9
100%|████████████████████████████████████| 10/10 [00:01<00:00, 9.20it/s]
Or if you want to have this behaviour of freezing the progress bar on its steps, you'll have to always print something afterwards, though i wouldn't really recommend this very much.
for i in tqdm(range(10), ncols=60):
time.sleep(1)
if i < 5:
print()
continue
print(' '*5+str(i))
0%| | 0/10 [00:00<?, ?it/s]
10%|██▍ | 1/10 [00:00<00:00, 9.41it/s]
20%|████▊ | 2/10 [00:00<00:00, 9.27it/s]
30%|███████▏ | 3/10 [00:00<00:00, 9.23it/s]
40%|█████████▌ | 4/10 [00:00<00:00, 9.26it/s]
50%|████████████ | 5/10 [00:00<00:00, 9.18it/s] 5
60%|██████████████▍ | 6/10 [00:00<00:00, 9.21it/s] 6
70%|████████████████▊ | 7/10 [00:00<00:00, 9.21it/s] 7
80%|███████████████████▏ | 8/10 [00:00<00:00, 9.18it/s] 8
90%|█████████████████████▌ | 9/10 [00:00<00:00, 9.16it/s] 9
100%|███████████████████████| 10/10 [00:01<00:00, 9.20it/s]
答案3
得分: 0
只返回翻译好的部分:
"这是一个单一的进度条应该在单一行上,但 tqdm 不处理其他写入控制台的功能,所以你会得到一个分段效果。正如 @Talon 所说,你可以使用 tqdm 的 write()
方法,它会移除进度条,写入控制台,并重新绘制进度条。
或者,你可以使用一个支持原生行为的不同进度条库,比如 Enlighten。
import time
import enlighten
manager = enlighten.Manager()
pbar = manager.counter(total=10)
for i in pbar(range(10)):
time.sleep(1)
print(' '*5+str(i))
英文:
It's a single progress bar are should be on single line, but tqdm doesn't handle other facilities writing to the console, so you get a stepped effect. As @Talon said, you can use tqdm's write()
method which removes the progress bar, writes to the console, and redraws the progress bar.
Alternatively, you can use a different progress bar library that supports the native behavior, like Enlighten
import time
import enlighten
manager = enlighten.Manager()
pbar = manager.counter(total=10)
for i in pbar(range(10)):
time.sleep(1)
print(' '*5+str(i))
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论