18

Python内のプログレスバーのさまざまなソリューションを見てきましたが、単純なstdoutソリューションが私のプロジェクトでは機能していません。複数のクラスがあり、「logging」モジュールを使用して情報をSTDOUTに出力します。プログレスバーを1行に表示して、毎回バッファをフラッシュする機能があります。

単純な進歩の例:

for i in range(100):
    time.sleep(1)
    sys.stdout.write("\r%d%%" %i)
    sys.stdout.flush()

STDOUTを介して書き込みを行ってからバッファをフラッシュしようとすると、バッファがフラッシュされないか、進行状況がどこにも行きません。これを可能にするために、ある種のスレッド化や複雑なプロセスを避けたいと思っています。誰かがこれを実現するための好ましい方法を持っていますか?

4

6 に答える 6

11

私はこのようにそれを解決しました:

import logging
import time
from tqdm import tqdm
import io

class TqdmToLogger(io.StringIO):
    """
        Output stream for TQDM which will output to logger module instead of
        the StdOut.
    """
    logger = None
    level = None
    buf = ''
    def __init__(self,logger,level=None):
        super(TqdmToLogger, self).__init__()
        self.logger = logger
        self.level = level or logging.INFO
    def write(self,buf):
        self.buf = buf.strip('\r\n\t ')
    def flush(self):
        self.logger.log(self.level, self.buf)

if __name__ == "__main__":
    logging.basicConfig(format='%(asctime)s [%(levelname)-8s] %(message)s')
    logger = logging.getLogger()
    logger.setLevel(logging.DEBUG)

    tqdm_out = TqdmToLogger(logger,level=logging.INFO)
    for x in tqdm(range(100),file=tqdm_out,mininterval=30,):
        time.sleep(.5)

出力

2016-12-19 15:35:06 [INFO    ] 16%|#####9                                | 768/4928 [07:04<40:50,  1.70it/s]
2016-12-19 15:36:07 [INFO    ] 18%|######6                               | 865/4928 [08:04<40:34,  1.67it/s]
于 2016-12-19T14:35:47.723 に答える
6

ここで説明されているように、ログを介してカスタム ハンドラーでtqdm プログレス バーを使用できます。

import logging
import time
import colorlog
from tqdm import tqdm

class TqdmHandler(logging.StreamHandler):
    def __init__(self):
        logging.StreamHandler.__init__(self)

    def emit(self, record):
        msg = self.format(record)
        tqdm.write(msg)

if __name__ == "__main__":
    for x in tqdm(range(100)):
        logger = colorlog.getLogger("MYAPP")
        logger.setLevel(logging.DEBUG)
        handler = TqdmHandler()
        handler.setFormatter(colorlog.ColoredFormatter(
            '%(log_color)s%(name)s | %(asctime)s | %(levelname)s | %(message)s',
            datefmt='%Y-%d-%d %H:%M:%S',
            log_colors={
                'DEBUG': 'cyan',
                'INFO': 'white',
                'SUCCESS:': 'green',
                'WARNING': 'yellow',
                'ERROR': 'red',
                'CRITICAL': 'red,bg_white'},))

        logger.addHandler(handler)
        logger.debug("Inside subtask: "+str(x))
        time.sleep(.5)
于 2016-08-11T11:46:05.143 に答える
1

進行状況バーが常に STDOUT に書き込まれることがわかっている場合printは、ロガーの代わりに使用する必要があります。Python ロギング チュートリアル ドキュメントのドキュメントを参照してください。

于 2013-02-15T15:25:31.697 に答える
0

プログレスバーを印刷しながらログを維持できるようにする、progressbar2を使用することもできます。

最小限の例:

import time
import progressbar

for i in progressbar.progressbar(range(100), redirect_stdout=True):
    print('Some text', i)
    time.sleep(0.1)

結果は次のとおりです。 結果のイメージ

(progressbar2 は Python2 と Python3 の両方と互換性があります)

于 2021-08-26T14:58:11.580 に答える
0

これらの提案のコードをクリーンアップします。これは IMO の正しい実装であり、外部依存関係はありません(こちらtqdmにも投稿されています):

import logging
from tqdm import tqdm


class TqdmLoggingHandler(logging.StreamHandler):
    """Avoid tqdm progress bar interruption by logger's output to console"""
    # see logging.StreamHandler.eval method:
    # https://github.com/python/cpython/blob/d2e2534751fd675c4d5d3adc208bf4fc984da7bf/Lib/logging/__init__.py#L1082-L1091
    # and tqdm.write method:
    # https://github.com/tqdm/tqdm/blob/f86104a1f30c38e6f80bfd8fb16d5fcde1e7749f/tqdm/std.py#L614-L620

    def emit(self, record):
        try:
            msg = self.format(record)
            tqdm.write(msg, end=self.terminator)
        except RecursionError:
            raise
        except Exception:
            self.handleError(record)

テスト:

import time

log = logging.getLogger(__name__)
log.setLevel(logging.INFO)
log.addHandler(TqdmLoggingHandler())
#   ^-- Assumes this will be the unique handler emitting messages to sys.stdout.
#       If other handlers output to sys.stdout (without tqdm.write),
#       progress bar will be interrupted by those outputs

for i in tqdm(range(20)):
    log.info(f"Looping {i}")
    time.sleep(0.1)
于 2021-04-25T20:13:11.560 に答える