首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >分离进度跟踪和循环逻辑

分离进度跟踪和循环逻辑
EN

Stack Overflow用户
提问于 2011-03-14 22:28:35
回答 3查看 1.1K关注 0票数 3

假设我想使用进度条打印机ProgressMeter (如此recipe中所述)跟踪循环的进度。

代码语言:javascript
复制
def bigIteration(collection):
    for element in collection:
        doWork(element)

我希望能够打开和关闭进度条。出于性能原因,我也想每x步更新一次。我天真的方法是

代码语言:javascript
复制
def bigIteration(collection, progressbar=True):
    if progressBar:
        pm = progress.ProgressMeter(total=len(collection))
        pc = 0
    for element in collection:
        if progressBar:
            pc += 1
            if pc % 100 = 0:
                pm.update(pc)
        doWork(element)

然而,我并不满意。从“美学”的角度来看,循环的功能代码现在被通用的进度跟踪代码“污染”了。

你能想出一种方法来清晰地分离进度跟踪代码和函数代码吗?(会不会有一个进度跟踪装饰器之类的?)

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2011-03-14 22:46:29

看起来这段代码将会从null object pattern中受益。

代码语言:javascript
复制
# a progress bar that uses ProgressMeter
class RealProgressBar:
     pm = Nothing
     def setMaximum(self, max):
         pm = progress.ProgressMeter(total=max)
         pc = 0
     def progress(self):
        pc += 1
        if pc % 100 = 0:
            pm.update(pc)

# a fake progress bar that does nothing
class NoProgressBar:
    def setMaximum(self, max):
         pass 
    def progress(self):
         pass

# Iterate with a given progress bar
def bigIteration(collection, progressBar=NoProgressBar()):
    progressBar.setMaximum(len(collection))
    for element in collection:
        progressBar.progress()
        doWork(element)

bigIteration(collection, RealProgressBar())

(请原谅我的法语,呃,Python不是我的母语;)不过,希望您能理解。)

这使您可以将进度更新逻辑从循环中移出,但其中仍有一些与进度相关的调用。

如果从在迭代时自动跟踪进度的集合创建生成器,则可以移除此部件。

代码语言:javascript
复制
 # turn a collection into one that shows progress when iterated
 def withProgress(collection, progressBar=NoProgressBar()):
      progressBar.setMaximum(len(collection))
      for element in collection:
           progressBar.progress();
           yield element

 # simple iteration function
 def bigIteration(collection):
    for element in collection:
        doWork(element)

 # let's iterate with progress reports
 bigIteration(withProgress(collection, RealProgressBar()))

这种方法使您的bigIteration函数保持不变,并且是高度可组合的。例如,假设您还想在您的大迭代中添加取消。只需创建另一个碰巧可取消的生成器。

代码语言:javascript
复制
# highly simplified cancellation token
# probably needs synchronization
class CancellationToken:
     cancelled = False
     def isCancelled(self):
         return cancelled
     def cancel(self):
         cancelled = True

# iterates a collection with cancellation support
def withCancellation(collection, cancelToken):
     for element in collection:
         if cancelToken.isCancelled():
             break
         yield element

progressCollection = withProgress(collection, RealProgressBar())
cancellableCollection = withCancellation(progressCollection, cancelToken)
bigIteration(cancellableCollection)

# meanwhile, on another thread...
cancelToken.cancel()
票数 6
EN

Stack Overflow用户

发布于 2011-03-14 22:45:14

您可以将bigIteration重写为生成器函数,如下所示:

代码语言:javascript
复制
def bigIteration(collection):
    for element in collection:
        doWork(element)
        yield element

然后,您可以在此之外做很多事情:

代码语言:javascript
复制
def mycollection = [1,2,3]
if progressBar:
    pm = progress.ProgressMeter(total=len(collection))
    pc = 0
    for item in bigIteration(mycollection):
        pc += 1
        if pc % 100 = 0:
            pm.update(pc)
else:
    for item in bigIteration(mycollection):
        pass
票数 2
EN

Stack Overflow用户

发布于 2011-03-14 22:43:52

我的方法是这样的:

每当循环代码发生变化(或需要报告)时,它都会生成进度百分比。然后,进度跟踪代码从生成器中读取,直到它为空;在每次读取之后更新进度条。

然而,这也有一些缺点:

  • 你需要一个函数在没有进度条的情况下调用它,因为你仍然需要从生成器中读取,直到它为空。
  • ,你不能很容易地在最后返回值。一种解决方案是包装返回值,这样progress方法就可以确定函数是否产生了进度更新或返回值。实际上,包装进度更新可能会更好,这样常规返回值就可以在未包装的情况下生成-但这需要更多的包装,因为它需要对每个进度更新进行包装,而不是只需要一次。
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/5299950

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档