Redirect print command in python script through tqdm.write()
我在Python中使用
但是,我必须调用那些同时向控制台发送
通常,在控制台中显示进度条时写入控制台会使显示混乱,如下所示:
1 2 3 4 5 6 7 8 9 | from time import sleep from tqdm import tqdm def blabla(): print"Foo blabla" for k in tqdm(range(3)): blabla() sleep(.5) |
这将创建输出:
1 2 3 4 5 6 7 | 0%| | 0/3 [00:00<?, ?it/s]Foo blabla 33%|###########6 | 1/3 [00:00<00:01, 2.00it/s]Foo blabla 67%|#######################3 | 2/3 [00:01<00:00, 2.00it/s]Foo blabla 100%|###################################| 3/3 [00:01<00:00, 2.00it/s] |
根据
因此,此代码段提供了正确的输出:
1 2 3 4 5 6 7 8 9 | from time import sleep from tqdm import tqdm def blabla(): tqdm.write("Foo blabla") for k in tqdm(range(3)): blabla() sleep(.5) |
看起来像这样:
1 2 3 4 | Foo blabla Foo blabla Foo blabla 100%|###################################| 3/3 [00:01<00:00, 1.99it/s] |
另一方面,存在这种解决方案,它允许通过相当优雅地将
这对于使功能静音非常有效。
由于我仍然希望显示这些功能的消息而又不破坏进度条,因此我尝试通过将
结果是代码段:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | from time import sleep import contextlib import sys from tqdm import tqdm class DummyFile(object): file = None def __init__(self, file): self.file = file def write(self, x): tqdm.write(x, file=self.file) @contextlib.contextmanager def nostdout(): save_stdout = sys.stdout sys.stdout = DummyFile(save_stdout) yield sys.stdout = save_stdout def blabla(): print"Foo blabla" for k in tqdm(range(3)): with nostdout(): blabla() sleep(.5) |
但是,这实际上会像以前一样产生更加混乱的输出:
1 2 3 4 5 6 7 8 9 10 11 12 13 | 0%| | 0/3 [00:00<?, ?it/s]Foo blabla 33%|###########6 | 1/3 [00:00<00:01, 2.00it/s]Foo blabla 67%|#######################3 | 2/3 [00:01<00:00, 2.00it/s]Foo blabla 100%|###################################| 3/3 [00:01<00:00, 2.00it/s] |
仅供参考:在
我不明白为什么这行不通,因为
我想念什么?
重定向
这里的技巧是默认情况下
因此,您只需要显式地将
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | from time import sleep import contextlib import sys from tqdm import tqdm class DummyFile(object): file = None def __init__(self, file): self.file = file def write(self, x): # Avoid print() second call (useless \ ) if len(x.rstrip()) > 0: tqdm.write(x, file=self.file) @contextlib.contextmanager def nostdout(): save_stdout = sys.stdout sys.stdout = DummyFile(sys.stdout) yield sys.stdout = save_stdout def blabla(): print("Foo blabla") # tqdm call to sys.stdout must be done BEFORE stdout redirection # and you need to specify sys.stdout, not sys.stderr (default) for _ in tqdm(range(3), file=sys.stdout): with nostdout(): blabla() sleep(.5) print('Done!') |
我还添加了一些技巧来使输出更好(例如,在没有
/ EDIT:实际上,看来您可以在启动
这可能是不好的方法,但是我更改了内置打印功能。
1 2 3 4 5 6 7 8 9 10 11 12 | import inspect import tqdm # store builtin print old_print = print def new_print(*args, **kwargs): # if tqdm.tqdm.write raises error, use builtin print try: tqdm.tqdm.write(*args, **kwargs) except: old_print(*args, ** kwargs) # globaly replace print with new_print inspect.builtins.print = new_print |
通过混合user493630和冗长的答案,我创建了此上下文管理器,从而避免了必须使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | import inspect import contextlib import tqdm @contextlib.contextmanager def redirect_to_tqdm(): # Store builtin print old_print = print def new_print(*args, **kwargs): # If tqdm.tqdm.write raises error, use builtin print try: tqdm.tqdm.write(*args, **kwargs) except: old_print(*args, ** kwargs) try: # Globaly replace print with new_print inspect.builtins.print = new_print yield finally: inspect.builtins.print = old_print |
要使用它,只需:
1 2 3 4 | for i in tqdm.tqdm(range(100)): with redirect_to_tqdm(): time.sleep(.1) print(i) |
为了进一步简化,可以将代码包装在新函数中:
1 2 3 4 5 6 7 8 | def tqdm_redirect(*args, **kwargs): with redirect_to_tqdm(): for x in tqdm.tqdm(*args, **kwargs): yield x for i in tqdm_redirect(range(20)): time.sleep(.1) print(i) |
OP的解决方案几乎是正确的。 tqdm库中使您的输出混乱的测试是这个(https://github.com/tqdm/tqdm/blob/master/tqdm/_tqdm.py#L546-L549):
1 2 3 4 | if hasattr(inst,"start_t") and (inst.fp == fp or all( f in (sys.stdout, sys.stderr) for f in (fp, inst. inst.clear(nolock=True) inst_cleared.append(inst) |
在此,测试
1 2 3 4 5 6 7 8 9 | class DummyFile(object): def __init__(self, file): self.file = file def write(self, x): tqdm.write(x, end="", file=self.file) def __eq__(self, other): return other is self.file |
另外,由于打印将换行符传递到
该解决方案的优势
用令人惊讶的答案,
有了Conchylicultor和user493630的回答,您才可以打补丁打印。但是,其他系统(例如日志记录)直接流式传输到sys.stdout,因此它们不会通过