这是上下文管理器的有效用例吗?

时间:2012-07-04 10:49:10

标签: python with-statement

我正在为一些长时间运行的控制台进程制作一个进度指示器,意图像这样使用它:

pi = ProgressIndicator()
for x in somelongstuff:
    do stuff
    pi.update()
pi.print_totals()

基本上,它应该输出某种带点和短划线的进度条,最后输出“234234字节处理”。

我认为将它用作上下文管理器会很好:

with ProgressIndicator() as pi:
    for x in somelongstuff:
       do stuff
       pi.update()

然而,有一些事情让我对这个解决方案感到担忧:

  • 额外缩进使得指标功能看起来比实际更重要
  • 我不希望ProgressIndicator处理循环中可能出现的任何异常

这是上下文管理器的有效用例吗?您能提出哪些其他解决方案?

2 个答案:

答案 0 :(得分:3)

这绝对是一个有效的用例。如果您不想要它,上下文管理器不必处理异常,尽管您希望结束输出进度条的行以防止它与回溯混淆,并且不打印总计如果通过例外退出。

关于缩进,我认为让用户看到进度实际上是一个非常重要的功能,因此它可以采用缩进级别。

答案 1 :(得分:2)

有一个GUI应用程序,它有一个非常相似的ProgressTask API,您可以这样使用:

def slow_func():
    t = nuke.ProgressTask()
    t.setMessage("Doing something")
    for x in range(100):
        do_something()
        t.setProgress(x+1)

调用ProgressTask.__del__时,进度条UI消失。这在大多数情况下都很好用,但是如果引发异常(例如do_something()),则回溯对象会保留对ProgressTask对象的引用,因此进度条会被卡住(直到另一个回溯发生时)

ProgressTask实现了上下文管理器协议,它可以使用__exit__方法来确保隐藏进度条。

对于命令行界面(听起来就像你在写),这可能不是问题,但你可以做类似的清理任务,例如显示######### 100% (error)类型栏,并确保追溯输出没有搞砸等

没有理由你的进度条类无法以两种方式使用 - 大多数上下文管理器完全可用作常规对象和上下文管理器,例如:

lock = threading.Lock()
lock.acquire()
lock.release()
# or:
with lock:
    pass