为什么在包含 continue 语句的 for 循环中 tqdm 进度条不起作用?

huangapple go评论115阅读模式
英文:

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))

几秒后,我在终端中看到以下显示,如预期:

为什么在包含 continue 语句的 for 循环中 tqdm 进度条不起作用?

在这里,print语句并不重要,只是一个计算(我只是使用print来显示计算已完成的事实)。

现在,我添加了一个continue语句,如下所示:

for i in tqdm(range(10)):
    time.sleep(1)
    if i < 5:
        continue
    print(' ' * 5 + str(i))

然后我得到了这个结果:

为什么在包含 continue 语句的 for 循环中 tqdm 进度条不起作用?

所以,我理解print语句在5以下的每次迭代都会被跳过,但是为什么进度条没有显示? 是否tqdm在循环结束时以某种方式添加了一个“显示进度条”的语句,因此这个顺序就像print语句一样被跳过了?我感觉好像tqdm仍然存储了进度条的数据(应该显示的那个进度条),所以它知道在continue语句不再执行后从哪里继续。

无论如何,我想知道是否有一种方法可以在每次迭代中打印进度条,即使在for循环内有一个continue语句,即使我的循环在第五次迭代之前都不会执行print(' ' * 5 + str(i))。只是为了清楚,我期望看到类似这样的东西:

为什么在包含 continue 语句的 for 循环中 tqdm 进度条不起作用?

请注意,这个显示了进度条在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(&#39; &#39;*5+str(i))

I get this displayed in the terminal after a few seconds:

为什么在包含 continue 语句的 for 循环中 tqdm 进度条不起作用?

, 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 &lt; 5:
        continue
    print(&#39; &#39;*5+str(i))

and I get this:

为什么在包含 continue 语句的 for 循环中 tqdm 进度条不起作用?

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(&#39; &#39;*5+str(i)) until it surpasses the fifth iteration of the loop. Just to be clear, I expect to see something like this:

为什么在包含 continue 语句的 for 循环中 tqdm 进度条不起作用?

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=&#39;\n{l_bar}{bar:20}{r_bar}&#39;):
    time.sleep(1)
    if i &lt; 5:
        continue
    print(&#39; &#39; * 5 + str(i), end=&#39;&#39;, flush=True)

Output:


  0%|                    | 0/10 [00:00&lt;?, ?it/s]
 10%|██                  | 1/10 [00:01&lt;00:09,  1.01s/it]
 20%|████                | 2/10 [00:02&lt;00:08,  1.01s/it]
 30%|██████              | 3/10 [00:03&lt;00:07,  1.01s/it]
 40%|████████            | 4/10 [00:04&lt;00:06,  1.00s/it]
 50%|██████████          | 5/10 [00:05&lt;00:05,  1.00s/it]     5
 60%|████████████        | 6/10 [00:06&lt;00:04,  1.01s/it]     6
 70%|██████████████      | 7/10 [00:07&lt;00:03,  1.00s/it]     7
 80%|████████████████    | 8/10 [00:08&lt;00:02,  1.00s/it]     8
 90%|██████████████████  | 9/10 [00:09&lt;00:01,  1.00s/it]     9
100%|████████████████████| 10/10 [00:10&lt;00:00,  1.00s/it]

Note the end=&#39;&#39; 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=&#39;\n{l_bar}{bar:20}{r_bar}&#39;):
    ...

答案2

得分: 0

`tqdm`想要覆盖先前的输出它会产生阶梯效应因为当`tqdm`不期望时您的`print`会手动添加换行符

如果您想发送一条消息以便它不干扰进度条您可以使用`write`,它会将您的消息放在进度条上方

```python
iterator = tqdm(range(10))
for i in iterator:
    time.sleep(0.1)
    if i &lt; 5:
        continue
    iterator.write(f&quot;迭代 {i}&quot;)
迭代 5
迭代 6
迭代 7
迭代 8
迭代 9
100%|████████████████████████████████████| 10/10 [00:01&lt;00:00,  9.20it/s]

或者,如果您想要具有在其步骤上“冻结”进度条的行为,您将不得不始终在此之后打印一些东西,尽管我并不真的推荐这样做。

for i in tqdm(range(10), ncols=60):
    time.sleep(1)
    if i &lt; 5:
        print()
        continue
    print(' '*5+str(i))
  0%|                                | 0/10 [00:00&lt;?, ?it/s]
 10%|██▍                     | 1/10 [00:00&lt;00:00,  9.41it/s]
 20%|████▊                   | 2/10 [00:00&lt;00:00,  9.27it/s]
 30%|███████▏                | 3/10 [00:00&lt;00:00,  9.23it/s]
 40%|█████████▌              | 4/10 [00:00&lt;00:00,  9.26it/s]
 50%|████████████            | 5/10 [00:00&lt;00:00,  9.18it/s]     5
 60%|██████████████▍         | 6/10 [00:00&lt;00:00,  9.21it/s]     6
 70%|████████████████▊       | 7/10 [00:00&lt;00:00,  9.21it/s]     7
 80%|███████████████████▏    | 8/10 [00:00&lt;00:00,  9.18it/s]     8
 90%|█████████████████████▌  | 9/10 [00:00&lt;00:00,  9.16it/s]     9
100%|███████████████████████| 10/10 [00:01&lt;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 &lt; 5:
        continue
    iterator.write(f&quot;iteration {i}&quot;)
iteration 5
iteration 6
iteration 7
iteration 8
iteration 9
100%|████████████████████████████████████| 10/10 [00:01&lt;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 &lt; 5:
        print()
        continue
    print(&#39; &#39;*5+str(i))
  0%|                                | 0/10 [00:00&lt;?, ?it/s]
 10%|██▍                     | 1/10 [00:00&lt;00:00,  9.41it/s]
 20%|████▊                   | 2/10 [00:00&lt;00:00,  9.27it/s]
 30%|███████▏                | 3/10 [00:00&lt;00:00,  9.23it/s]
 40%|█████████▌              | 4/10 [00:00&lt;00:00,  9.26it/s]
 50%|████████████            | 5/10 [00:00&lt;00:00,  9.18it/s]     5
 60%|██████████████▍         | 6/10 [00:00&lt;00:00,  9.21it/s]     6
 70%|████████████████▊       | 7/10 [00:00&lt;00:00,  9.21it/s]     7
 80%|███████████████████▏    | 8/10 [00:00&lt;00:00,  9.18it/s]     8
 90%|█████████████████████▌  | 9/10 [00:00&lt;00:00,  9.16it/s]     9
100%|███████████████████████| 10/10 [00:01&lt;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(&#39; &#39;*5+str(i))

huangapple
  • 本文由 发表于 2023年6月19日 18:40:33
  • 转载请务必保留本文链接:https://go.coder-hub.com/76505834.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定