简体   繁体   English

在 while 循环中使用 tqdm 进度条

[英]Using tqdm progress bar in a while loop

I am making a code that simulates a pawn going around a monopoly board a million times.我正在编写一个代码来模拟一个棋子在垄断板上转了一百万次。 I would like to have a tqdm progress bar that is updated every time a turn around the board is achieved.我想要一个 tqdm 进度条,每次完成转盘时都会更新。

Below is my current code.以下是我当前的代码。 I am using a while loop which stops when the number of turns around the board surpasses the desired number.我正在使用一个while循环,当电路板的转数超过所需数量时它会停止。

import os
from openpyxl import Workbook
from monopolyfct import *


def main(runs, fileOutput):

    ### EXCEL SETUP ###
    theWorkbook = Workbook()                              # Creates the workbook interface.
    defaultSheet = theWorkbook.active                     # Creates the used worksheet.
    currentData = ["Current Table Turn", "Current Tile"]  # Makes EXCEL column titles.
    defaultSheet.append(currentData)                      # Appends column titles.

    ### CONTENT SETUP ###
    currentData = [1, 0]             # Sets starting position.
    defaultSheet.append(currentData) # Appends starting position.

    while currentData[0] <= runs:

        ### ROLLING THE DICES PROCESS ###
        dices = twinDiceRoll()
        currentData[1] += dices[2]  # Updating the current tile

        ### SURPASSING THE NUMBER OF TILES ONBOARD ###
        if currentData[1] > 37:   # If more than a table turn is achieved,
            currentData[0] += 1   # One more turn is registered
            currentData[1] -= 38  # Update the tile to one coresponding to a board tile.
        else:
            pass

        ### APPENDING AQUIRED DATA ###
        defaultSheet.append(currentData)

        ### MANAGIING SPECIAL TILES ###
        if currentData[1] == 2 or 15 or 31:   # Community chess
            pass                              #TODO: Make a mechanic simulating the community chest card draw and it's related action.
        elif currentData[1] == 5 or 20 or 34: # Chance
            pass                              #TODO: Make a mechanic simulating the chance card draw and it's related action.
        elif currentData[1] == 28:            # Go to Jail
            pass                              #TODO: Make a mechanic simulating the entire jail process

        ### TWIN DICE ROLL EXCEPTION ###
        if dices[3] is True:  # If the dices roll a double,
            pass              #TODO: Make a mechanic considering that three doubles sends one to Jail.


    ### STORING THE ACCUMULATED DATA ###
    theWorkbook.save(fileOutput)  # Compiles the data in a .xlxs file.


if __name__ == "__main__":
    terminalWidth = os.get_terminal_size().columns                                               # Gets current terminal width.
    space(3)
    print("Python Monopoly Statistics Renderer".upper().center(terminalWidth))                   # Prints the title.
    print("(PMSR)".center(terminalWidth))                                                        # Prints the acronym.
    space(2)
    runs = int(request("For how many table turns do you want the simulation to run?"))           # Prompts for the desired run ammount
    #runs = 1000
    fileOutput = request("What should be the name of the file in which statistics are stored?")  # Prompts for the desired store filename
    #fileOutput = "test"
    fileOutput += ".xlsx"                                                                        # Adds file extension to filename
    main(runs, fileOutput)

You can use manual control in tqdm by specifying a total argument in the constructor.您可以通过在构造函数中指定total参数来在tqdm使用手动控制。 Verbatim from the manual :手册中的逐字逐句:

with tqdm(total=100) as pbar:
    for i in range(10):
        sleep(0.1)
        pbar.update(10)

UPDATE更新

To manually control the tqdm without the context manager (aka with statement), you will need to close the progress bar after you are done using it.要在没有上下文管理器(又名with语句)的情况下手动控制tqdm ,您需要在使用完成后关闭进度条。 Here is another example from the manual:这是手册中的另一个示例:

pbar = tqdm(total=100)
for i in range(10):
    sleep(0.1)
    pbar.update(10)
pbar.close()

For this to work you need to know the total number of expected runs.为此,您需要知道预期运行的总数。 In your code it could look something like在您的代码中,它可能看起来像

...
pbar = tqdm(total = runs+1)
while currentData[0] <= runs:

    ### ROLLING THE DICES PROCESS ###
    dices = twinDiceRoll()
    currentData[1] += dices[2]  # Updating the current tile

    ### SURPASSING THE NUMBER OF TILES ONBOARD ###
    if currentData[1] > 37:   # If more than a table turn is achieved,
        currentData[0] += 1   # One more turn is registered
        currentData[1] -= 38  # Update the tile to one coresponding to a board tile.
        pbar.update(1)
    else:
        pass
...
pbar.close()

However, this code isn't perfect: consider if the currentData[1] is always less than 37 -- the progress bar will just stop and not update.然而,这段代码并不完美:考虑currentData[1]是否总是小于currentData[1]进度条只会停止而不更新。 If you try to update it in the else:... part, you might violate the total upper bound.如果您尝试在else:...部分更新它,您可能会违反total上限。 This is a start tho :)这是一个开始 :)

Because of the attention, this post is attracting I thought it would be good to point out how this can be achieved with an infinite while loop as well.由于受到关注,这篇文章很吸引我,我认为最好指出如何通过无限 while 循环来实现这一点。

To use an infinite loop with tqdm you need to change your while loop into an infinite for loop by utilizing a generator.要在 tqdm 中使用无限循环,您需要使用生成器将 while 循环更改为无限 for 循环。

Infinite loop (no progress bar)无限循环(无进度条)

while True:
  # Do stuff here

Infinite loop (with progress bar)无限循环(带进度条)

def generator():
  while True:
    yield

for _ in tqdm(generator()):
  # Do stuff here

The code above would create an indefinite progress bar that would look similar to this上面的代码将创建一个与此类似的无限进度条

16it [01:38,  6.18s/it]

Note that the generator could also be modified to work with a condition请注意,生成器也可以修改为使用条件

def generator():
  while condition:
    yield

An additional version for user12128336's answer. user12128336 的答案的附加版本。

You can do all iteration stuff inside a generator.您可以在生成器中执行所有迭代操作。 Just add yield at the end of iteration.只需在迭代结束时添加yield

from tqdm.auto import tqdm
from time import sleep


def generator():
    while True:
        sleep(0.3) # iteration stuff
        yield
        
for _ in tqdm(generator()): pass

# 77it [00:23,  3.25it/s]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM