Pie*_*der 13 python python-2.7 tqdm
我正在使用tqdm
Python在我们的脚本中显示控制台进度条.但是,我必须将调用print
消息的函数调用到控制台,而且我无法更改.通常,在控制台中显示进度条的同时写入控制台会使显示屏变得如此:
from time import sleep
from tqdm import tqdm
def blabla():
print "Foo blabla"
for k in tqdm(range(3)):
blabla()
sleep(.5)
Run Code Online (Sandbox Code Playgroud)
这会创建输出:
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]
Run Code Online (Sandbox Code Playgroud)
根据tqdm
该方法的文档tqdm.write()
提供了一种在不破坏显示的进度条的情况下将消息写入控制台的方法.因此,此片段提供了正确的输出:
from time import sleep
from tqdm import tqdm
def blabla():
tqdm.write("Foo blabla")
for k in tqdm(range(3)):
blabla()
sleep(.5)
Run Code Online (Sandbox Code Playgroud)
看起来像这样:
Foo blabla
Foo blabla
Foo blabla
100%|###################################| 3/3 [00:01<00:00, 1.99it/s]
Run Code Online (Sandbox Code Playgroud)
另一方面,有这种解决方案允许通过非常优雅地重定向sys.stdout
到空隙中来使这些功能静音.这非常适合静音功能.
因为我想显示来自这些函数的消息而不打破进度条,我试图通过重定向sys.stdout
到两个解决方案tqdm.write()
,然后让它们tqdm.write()
写入旧的 sys.stdout
.这导致代码段:
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)
Run Code Online (Sandbox Code Playgroud)
但是,这实际上会像以前一样创建一个更加混乱的输出:
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]
Run Code Online (Sandbox Code Playgroud)
仅供参考:调用tqdm.write(..., end="")
内部DummyFile.write()
会产生与第一个仍然混乱的输出相同的结果.
我无法理解为什么这不起作用,因为tqdm.write()
应该在编写消息之前管理清除进度条,然后重写进度条.
我错过了什么?
gab*_*ous 17
重定向sys.stdout
总是很棘手,当两个应用程序同时使用它时,它变成了一场噩梦.
这里的诀窍是tqdm
默认情况下打印到sys.stderr
,而不是sys.stdout
.通常,tqdm
对于这两个特殊通道有一个反混淆策略,但由于您重定向sys.stdout
,tqdm
因为文件句柄发生变化而感到困惑.
因此,你只需要明确指定file=sys.stdout
要tqdm
和它的工作:
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 \n)
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!')
Run Code Online (Sandbox Code Playgroud)
我还增加了一些技巧,让输出更好的(例如,没有无用的\n
使用时print()
无end=''
).
/编辑:其实好像你可以做stdout
启动后重定向tqdm
,您只需要指定dynamic_ncols=True
的tqdm
.
通过混合,user493630和gaborous答案,我创建了避免使用在这种情况下管理者file=sys.stdout
的参数tqdm
。
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
Run Code Online (Sandbox Code Playgroud)
要使用它,只需:
for i in tqdm.tqdm(range(100)):
with redirect_to_tqdm():
time.sleep(.1)
print(i)
Run Code Online (Sandbox Code Playgroud)
为了进一步简化,可以将代码包装在一个新函数中:
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)
Run Code Online (Sandbox Code Playgroud)
小智 6
这可能是坏方法,但我改变了内置的打印功能.
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
Run Code Online (Sandbox Code Playgroud)