假设我想使用进度条打印机ProgressMeter (如此recipe中所述)跟踪循环的进度。
def bigIteration(collection):
for element in collection:
doWork(element)我希望能够打开和关闭进度条。出于性能原因,我也想每x步更新一次。我天真的方法是
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)然而,我并不满意。从“美学”的角度来看,循环的功能代码现在被通用的进度跟踪代码“污染”了。
你能想出一种方法来清晰地分离进度跟踪代码和函数代码吗?(会不会有一个进度跟踪装饰器之类的?)
发布于 2011-03-14 22:46:29
看起来这段代码将会从null object pattern中受益。
# 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不是我的母语;)不过,希望您能理解。)
这使您可以将进度更新逻辑从循环中移出,但其中仍有一些与进度相关的调用。
如果从在迭代时自动跟踪进度的集合创建生成器,则可以移除此部件。
# 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函数保持不变,并且是高度可组合的。例如,假设您还想在您的大迭代中添加取消。只需创建另一个碰巧可取消的生成器。
# 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()发布于 2011-03-14 22:45:14
您可以将bigIteration重写为生成器函数,如下所示:
def bigIteration(collection):
for element in collection:
doWork(element)
yield element然后,您可以在此之外做很多事情:
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发布于 2011-03-14 22:43:52
我的方法是这样的:
每当循环代码发生变化(或需要报告)时,它都会生成进度百分比。然后,进度跟踪代码从生成器中读取,直到它为空;在每次读取之后更新进度条。
然而,这也有一些缺点:
https://stackoverflow.com/questions/5299950
复制相似问题