سؤال

هل هناك طريقة جيدة للقيام بما يلي؟

لقد كتبت تطبيق وحدة تحكم بسيط لتحميل الملفات وتنزيلها من خادم FTP باستخدام FTPLIB.

في كل مرة يتم تنزيل بعض قطع البيانات ، أريد تحديث شريط تقدم النص ، حتى لو كان مجرد رقم.

لكني لا أريد محو كل النصوص التي تمت طباعتها على وحدة التحكم. (القيام "واضح" ثم طباعة النسبة المئوية المحدثة.)

هل كانت مفيدة؟

المحلول

شريط تقدم بسيط وقابل للتخصيص

إليك مجموعة من الإجابات أدناه التي أستخدمها بانتظام (لا توجد واردات مطلوبة).

# Print iterations progress
def printProgressBar (iteration, total, prefix = '', suffix = '', decimals = 1, length = 100, fill = '█'):
    """
    Call in a loop to create terminal progress bar
    @params:
        iteration   - Required  : current iteration (Int)
        total       - Required  : total iterations (Int)
        prefix      - Optional  : prefix string (Str)
        suffix      - Optional  : suffix string (Str)
        decimals    - Optional  : positive number of decimals in percent complete (Int)
        length      - Optional  : character length of bar (Int)
        fill        - Optional  : bar fill character (Str)
    """
    percent = ("{0:." + str(decimals) + "f}").format(100 * (iteration / float(total)))
    filledLength = int(length * iteration // total)
    bar = fill * filledLength + '-' * (length - filledLength)
    print('\r%s |%s| %s%% %s' % (prefix, bar, percent, suffix), end = '\r')
    # Print New Line on Complete
    if iteration == total: 
        print()

ملحوظة: هذا لبيثون 3 ؛ انظر التعليقات للحصول على تفاصيل حول استخدام هذا في بيثون 2.

استخدام العينة

import time

# A List of Items
items = list(range(0, 57))
l = len(items)

# Initial call to print 0% progress
printProgressBar(0, l, prefix = 'Progress:', suffix = 'Complete', length = 50)
for i, item in enumerate(items):
    # Do stuff...
    time.sleep(0.1)
    # Update Progress Bar
    printProgressBar(i + 1, l, prefix = 'Progress:', suffix = 'Complete', length = 50)

إخراج العينة:

Progress: |█████████████████████████████████████████████-----| 90.0% Complete

تحديث

كان هناك نقاش في التعليقات المتعلقة بخيار يسمح لبرنامج التقدم بالضبط ديناميكيًا مع عرض النافذة الطرفية. على الرغم من أنني لا أوصي بهذا ، إليك ملف جوهر هذا ينفذ هذه الميزة (ويلاحظ المحاذير).

نصائح أخرى

ستنقل كتابة " r" المؤشر إلى بداية الخط.

هذا يعرض عداد النسبة المئوية:

import time
import sys

for i in range(100):
    time.sleep(1)
    sys.stdout.write("\r%d%%" % i)
    sys.stdout.flush()

TQDM: أضف مقياس تقدم إلى حلقاتك في الثانية:

>>> import time
>>> from tqdm import tqdm
>>> for i in tqdm(range(100)):
...     time.sleep(1)
... 
|###-------| 35/100  35% [elapsed: 00:35 left: 01:05,  1.00 iters/sec]

tqdm repl session

اكتب \r إلى وحدة التحكم. هذا هو "إرجاع" الذي يسبب كل النص بعد أن يتم صدىه في بداية الخط. شيء مثل:

def update_progress(progress):
    print '\r[{0}] {1}%'.format('#'*(progress/10), progress)

الذي سيعطيك شيئًا مثل: [ ########## ] 100%

هو أقل من 10 أسطر من التعليمات البرمجية.

جوهر هنا: https://gist.github.com/vladignatyev/06860ec2040cb497f0f3

import sys


def progress(count, total, suffix=''):
    bar_len = 60
    filled_len = int(round(bar_len * count / float(total)))

    percents = round(100.0 * count / float(total), 1)
    bar = '=' * filled_len + '-' * (bar_len - filled_len)

    sys.stdout.write('[%s] %s%s ...%s\r' % (bar, percents, '%', suffix))
    sys.stdout.flush()  # As suggested by Rom Ruben

enter image description here

جرب ال انقر مكتبة كتبها موزارت بيثون ، أرمين رونشر.

$ pip install click # both 2 and 3 compatible

لإنشاء شريط تقدم بسيط:

import click

with click.progressbar(range(1000000)) as bar:
    for i in bar:
        pass 

هذا ما يبدو عليه:

# [###-------------------------------]    9%  00:01:14

تخصيص محتوى قلوبك:

import click, sys

with click.progressbar(range(100000), file=sys.stderr, show_pos=True, width=70, bar_template='(_(_)=%(bar)sD(_(_| %(info)s', fill_char='=', empty_char=' ') as bar:
    for i in bar:
        pass

نظرة مخصصة:

(_(_)===================================D(_(_| 100000/100000 00:00:02

هناك المزيد من الخيارات ، انظر مستندات API:

 click.progressbar(iterable=None, length=None, label=None, show_eta=True, show_percent=None, show_pos=False, item_show_func=None, fill_char='#', empty_char='-', bar_template='%(label)s [%(bar)s] %(info)s', info_sep=' ', width=36, file=None, color=None)

أدرك أنني تأخرت عن اللعبة ، لكن إليك واحدة من طراز Yum (Hat Red Hat) التي كتبتها (لا أذهب إلى دقة 100 ٪ هنا ، ولكن إذا كنت تستخدم شريط تقدم لهذا المستوى من الدقة ، فأنت أنت 'إعادة خطأ على أي حال):

import sys

def cli_progress_test(end_val, bar_length=20):
    for i in xrange(0, end_val):
        percent = float(i) / end_val
        hashes = '#' * int(round(percent * bar_length))
        spaces = ' ' * (bar_length - len(hashes))
        sys.stdout.write("\rPercent: [{0}] {1}%".format(hashes + spaces, int(round(percent * 100))))
        sys.stdout.flush()

يجب أن تنتج شيئًا يبدو مثل هذا:

Percent: [##############      ] 69%

... حيث تبقى الأقواس ثابتة وفقط تجزئة يزداد.

هذا قد يعمل بشكل أفضل كديكور. ليوم آخر...

تحقق من هذه المكتبة: كلينت

لديها الكثير من الميزات بما في ذلك شريط التقدم:

from time import sleep  
from random import random  
from clint.textui import progress  
if __name__ == '__main__':
    for i in progress.bar(range(100)):
        sleep(random() * 0.2)

    for i in progress.dots(range(100)):
        sleep(random() * 0.2)

هذه حلقة الوصل يوفر نظرة عامة سريعة على ميزاته

إليكم مثالًا رائعًا على شريط تقدم مكتوب في بيثون: http://nadiana.com/animated-terminal-progress-bar-in-python

ولكن إذا كنت تريد أن تكتبها بنفسك. يمكنك استخدام curses الوحدة لتسهيل الأمور :)

تحرير] ربما أسهل ليست كلمة اللعنات. ولكن إذا كنت ترغب في إنشاء CUI الكامل من اللعنات ، فإن العناية بالكثير من الأشياء لك.

تحرير] نظرًا لأن الرابط القديم قد مات ، فقد وضعت نسختي الخاصة من Python ProgressBar ، احصل عليها هنا: https://github.com/wolph/python-progressbar

import time,sys

for i in range(100+1):
    time.sleep(0.1)
    sys.stdout.write(('='*i)+(''*(100-i))+("\r [ %d"%i+"% ] "))
    sys.stdout.flush()

انتاج

[ 29% ] ===================

ولمجرد إضافة إلى الكومة ، إليك كائن يمكنك استخدامه

import sys

class ProgressBar(object):
    DEFAULT_BAR_LENGTH = 65
    DEFAULT_CHAR_ON  = '='
    DEFAULT_CHAR_OFF = ' '

    def __init__(self, end, start=0):
        self.end    = end
        self.start  = start
        self._barLength = self.__class__.DEFAULT_BAR_LENGTH

        self.setLevel(self.start)
        self._plotted = False

    def setLevel(self, level):
        self._level = level
        if level < self.start:  self._level = self.start
        if level > self.end:    self._level = self.end

        self._ratio = float(self._level - self.start) / float(self.end - self.start)
        self._levelChars = int(self._ratio * self._barLength)

    def plotProgress(self):
        sys.stdout.write("\r  %3i%% [%s%s]" %(
            int(self._ratio * 100.0),
            self.__class__.DEFAULT_CHAR_ON  * int(self._levelChars),
            self.__class__.DEFAULT_CHAR_OFF * int(self._barLength - self._levelChars),
        ))
        sys.stdout.flush()
        self._plotted = True

    def setAndPlot(self, level):
        oldChars = self._levelChars
        self.setLevel(level)
        if (not self._plotted) or (oldChars != self._levelChars):
            self.plotProgress()

    def __add__(self, other):
        assert type(other) in [float, int], "can only add a number"
        self.setAndPlot(self._level + other)
        return self
    def __sub__(self, other):
        return self.__add__(-other)
    def __iadd__(self, other):
        return self.__add__(other)
    def __isub__(self, other):
        return self.__add__(-other)

    def __del__(self):
        sys.stdout.write("\n")

if __name__ == "__main__":
    import time
    count = 150
    print "starting things:"

    pb = ProgressBar(count)

    #pb.plotProgress()
    for i in range(0, count):
        pb += 1
        #pb.setAndPlot(i + 1)
        time.sleep(0.01)
    del pb

    print "done"

النتائج في:

starting things:
  100% [=================================================================]
done

سيكون هذا الأمر أكثر شيوعًا "على القمة" ، لكنه مفيد عندما تستخدمه كثيرًا

تشغيل هذا في سطر أوامر بيثون (ليس في أي IDE أو بيئة تنمية):

>>> import threading
>>> for i in range(50+1):
...   threading._sleep(0.5)
...   print "\r%3d" % i, ('='*i)+('-'*(50-i)),

يعمل بشكل جيد على نظام Windows الخاص بي.

تثبيت tqdm.(pip install tqdm) واستخدامه على النحو التالي:

import time
from tqdm import tqdm
for i in tqdm(range(1000)):
    time.sleep(0.01)

هذا هو شريط التقدم 10 ثوانٍ سيؤدي إلى إخراج شيء من هذا القبيل:

47%|██████████████████▊                     | 470/1000 [00:04<00:05, 98.61it/s]

والكثير من البرامج التعليمية التي تنتظر أن تكون غوغل.

انا استخدم التقدم من رديت. يعجبني ذلك لأنه يمكن أن يطبع التقدم لكل عنصر في سطر واحد ، ويجب ألا يمحو المطبوعات من البرنامج.

تحرير: رابط ثابت

استنادًا إلى الإجابات المذكورة أعلاه وغيرها من الأسئلة المماثلة حول CLI Progress Bar ، أعتقد أنني حصلت على إجابة شائعة عامة على كل منها. تحقق من ذلك في https://stackoverflow.com/a/15860757/2254146

باختصار ، الرمز هو:

import time, sys

# update_progress() : Displays or updates a console progress bar
## Accepts a float between 0 and 1. Any int will be converted to a float.
## A value under 0 represents a 'halt'.
## A value at 1 or bigger represents 100%
def update_progress(progress):
    barLength = 10 # Modify this to change the length of the progress bar
    status = ""
    if isinstance(progress, int):
        progress = float(progress)
    if not isinstance(progress, float):
        progress = 0
        status = "error: progress var must be float\r\n"
    if progress < 0:
        progress = 0
        status = "Halt...\r\n"
    if progress >= 1:
        progress = 1
        status = "Done...\r\n"
    block = int(round(barLength*progress))
    text = "\rPercent: [{0}] {1}% {2}".format( "#"*block + "-"*(barLength-block), progress*100, status)
    sys.stdout.write(text)
    sys.stdout.flush()

يشبه

في المئة: [#########] 99.0 ٪

أوصي باستخدام TQDM - https://pypi.python.org/pypi/tqdm - مما يجعل من السهل تحويل أي أمر لا يطاق أو معالجة إلى شريط تقدم ، ويتعامل مع كل العبث مع المحطات المطلوبة.

من الوثائق: "يمكن لـ TQDM بسهولة دعم عمليات الاسترجاعات/السنانير والتحديثات اليدوية. إليك مثال مع Urllib"

import urllib
from tqdm import tqdm

def my_hook(t):
  """
  Wraps tqdm instance. Don't forget to close() or __exit__()
  the tqdm instance once you're done with it (easiest using `with` syntax).

  Example
  -------

  >>> with tqdm(...) as t:
  ...     reporthook = my_hook(t)
  ...     urllib.urlretrieve(..., reporthook=reporthook)

  """
  last_b = [0]

  def inner(b=1, bsize=1, tsize=None):
    """
    b  : int, optional
        Number of blocks just transferred [default: 1].
    bsize  : int, optional
        Size of each block (in tqdm units) [default: 1].
    tsize  : int, optional
        Total size (in tqdm units). If [default: None] remains unchanged.
    """
    if tsize is not None:
        t.total = tsize
    t.update((b - last_b[0]) * bsize)
    last_b[0] = b
  return inner

eg_link = 'http://www.doc.ic.ac.uk/~cod11/matryoshka.zip'
with tqdm(unit='B', unit_scale=True, miniters=1,
          desc=eg_link.split('/')[-1]) as t:  # all optional kwargs
    urllib.urlretrieve(eg_link, filename='/dev/null',
                       reporthook=my_hook(t), data=None)

حاول تثبيت هذه الحزمة: pip install progressbar2 :

import time
import progressbar

for i in progressbar.progressbar(range(100)):
    time.sleep(0.02)

Progressbar Github: https://github.com/wolph/python-progressbar

import sys
def progresssbar():
         for i in range(100):
            time.sleep(1)
            sys.stdout.write("%i\r" % i)

progressbar()

ملاحظة: إذا قمت بتشغيل هذا في Intereactive Interpter ، فستحصل على أرقام إضافية مطبوعة

لول ، لقد كتبت للتو شيئًا كاملًا لهذه البدعة ، تضع الرمز في الاعتبار أنه لا يمكنك استخدام Unicode عند القيام بلوك ASCII ، أستخدم CP437

import os
import time
def load(left_side, right_side, length, time):
    x = 0
    y = ""
    print "\r"
    while x < length:
        space = length - len(y)
        space = " " * space
        z = left + y + space + right
        print "\r", z,
        y += "█"
        time.sleep(time)
        x += 1
    cls()

وأنت تسميها مثل ذلك

print "loading something awesome"
load("|", "|", 10, .01)

لذلك يبدو هكذا

loading something awesome
|█████     |

مع النصائح الرائعة أعلاه ، أعمل على شريط التقدم.

ومع ذلك أود أن أشير إلى بعض أوجه القصور

  1. في كل مرة يتم فيها مسح شريط التقدم ، سيبدأ على خط جديد

    print('\r[{0}]{1}%'.format('#' * progress* 10, progress))  
    

    مثله:
    [] 0%
    [#]10%
    [##]20%
    [###]30%

2. القوس المربع "] وعدد النسبة المئوية على الجانب الأيمن يمينًا حيث يزداد "###" لفترة أطول.
3. سيحدث خطأ إذا لم يتمكن التعبير "تقدم / 10" من إرجاع عدد صحيح.

وسيقوم الرمز التالي بإصلاح المشكلة أعلاه.

def update_progress(progress, total):  
    print('\r[{0:10}]{1:>2}%'.format('#' * int(progress * 10 /total), progress), end='')

الحل البسيط للغاية هو وضع هذا الرمز في حلقتك:

ضع هذا في الجسم (أي أعلى) من ملفك:

import sys

ضع هذا في جسم حلقتك:

sys.stdout.write("-") # prints a dash for each iteration of loop
sys.stdout.flush() # ensures bar is displayed incrementally

رمز شريط التقدم الطرفي بيثون

import sys
import time

max_length = 5
at_length = max_length
empty = "-"
used = "%"

bar = empty * max_length

for i in range(0, max_length):
    at_length -= 1

    #setting empty and full spots
    bar = used * i
    bar = bar+empty * at_length

    #\r is carriage return(sets cursor position in terminal to start of line)
    #\0 character escape

    sys.stdout.write("[{}]\0\r".format(bar))
    sys.stdout.flush()

    #do your stuff here instead of time.sleep
    time.sleep(1)

sys.stdout.write("\n")
sys.stdout.flush()

وضع بعض الأفكار التي وجدتها هنا ، وإضافة الوقت المقدر المتبقي:

import datetime, sys

start = datetime.datetime.now()

def print_progress_bar (iteration, total):

    process_duration_samples = []
    average_samples = 5

    end = datetime.datetime.now()

    process_duration = end - start

    if len(process_duration_samples) == 0:
        process_duration_samples = [process_duration] * average_samples

    process_duration_samples = process_duration_samples[1:average_samples-1] + [process_duration]
    average_process_duration = sum(process_duration_samples, datetime.timedelta()) / len(process_duration_samples)
    remaining_steps = total - iteration
    remaining_time_estimation = remaining_steps * average_process_duration

    bars_string = int(float(iteration) / float(total) * 20.)
    sys.stdout.write(
        "\r[%-20s] %d%% (%s/%s) Estimated time left: %s" % (
            '='*bars_string, float(iteration) / float(total) * 100,
            iteration,
            total,
            remaining_time_estimation
        ) 
    )
    sys.stdout.flush()
    if iteration + 1 == total:
        print 


# Sample usage

for i in range(0,300):
    print_progress_bar(i, 300)

حسنًا ، هنا رمز يعمل واختبرته قبل النشر:

import sys
def prg(prog, fillchar, emptchar):
    fillt = 0
    emptt = 20
    if prog < 100 and prog > 0:
        prog2 = prog/5
        fillt = fillt + prog2
        emptt = emptt - prog2
        sys.stdout.write("\r[" + str(fillchar)*fillt + str(emptchar)*emptt + "]" + str(prog) + "%")
        sys.stdout.flush()
    elif prog >= 100:
        prog = 100
        prog2 = prog/5
        fillt = fillt + prog2
        emptt = emptt - prog2
        sys.stdout.write("\r[" + str(fillchar)*fillt + str(emptchar)*emptt + "]" + str(prog) + "%" + "\nDone!")
        sys.stdout.flush()
    elif prog < 0:
        prog = 0
        prog2 = prog/5
        fillt = fillt + prog2
        emptt = emptt - prog2
        sys.stdout.write("\r[" + str(fillchar)*fillt + str(emptchar)*emptt + "]" + str(prog) + "%" + "\nHalted!")
        sys.stdout.flush()

الايجابيات:

  • 20 حرفًا (حرف واحد لكل 5 (رقم حكيمة))
  • شخصيات ملء مخصصة
  • أحرف فارغة مخصصة
  • توقف (أي رقم أقل من 0)
  • تم (100 وأي رقم فوق 100)
  • عدد التقدم (0-100 (أدناه وما فوق يستخدم لوظائف خاصة))
  • عدد النسبة المئوية بجانب الشريط ، وهو سطر واحد

سلبيات:

  • يدعم الأعداد الصحيحة فقط (يمكن تعديلها لدعمهم ، من خلال جعل القسم تقسيم عدد صحيح ، لذلك فقط التغيير prog2 = prog/5 إلى prog2 = int(prog/5))

ها هو حل بيثون 3 الخاص بي:

import time
for i in range(100):
    time.sleep(1)
    s = "{}% Complete".format(i)
    print(s,end=len(s) * '\b')

' b' هو ملاذ خلفي ، لكل حرف في السلسلة الخاصة بك. هذا لا يعمل داخل نافذة Windows CMD.

وظيفة من Greenstick لمدة 2.7:

def printProgressBar (iteration, total, prefix = '', suffix = '',decimals = 1, length = 100, fill = '#'):

percent = ("{0:." + str(decimals) + "f}").format(100 * (iteration / float(total)))
filledLength = int(length * iteration // total)
bar = fill * filledLength + '-' * (length - filledLength)
print'\r%s |%s| %s%% %s' % (prefix, bar, percent, suffix),
sys.stdout.flush()
# Print New Line on Complete                                                                                                                                                                                                              
if iteration == total:
    print()

وحدة بيثون شريط التقدم هو اختيار لطيف. هذا هو الكود النموذجي الخاص بي:

import time
import progressbar

widgets = [
    ' ', progressbar.Percentage(),
    ' ', progressbar.SimpleProgress(format='(%(value_s)s of %(max_value_s)s)'),
    ' ', progressbar.Bar('>', fill='.'),
    ' ', progressbar.ETA(format_finished='- %(seconds)s  -', format='ETA: %(seconds)s', ),
    ' - ', progressbar.DynamicMessage('loss'),
    ' - ', progressbar.DynamicMessage('error'),
    '                          '
]

bar = progressbar.ProgressBar(redirect_stdout=True, widgets=widgets)
bar.start(100)
for i in range(100):
    time.sleep(0.1)
    bar.update(i + 1, loss=i / 100., error=i)
bar.finish()

https://pypi.python.org/pypi/ProgressBar2/3.30.2

ProgressBar2 هي مكتبة جيدة لـ ASCII Base ProgressBar لوقت استيراد سطر الأوامر

bar = progressbar.ProgressBar()
for i in bar(range(100)):
    time.sleep(0.02)
bar.finish()

https://pypi.python.org/pypi/tqdm

TQDM هو بديل لـ ProgressBar2 وأعتقد أنه يستخدم في PIP3 لكنني لست متأكدًا من ذلك

from tqdm import tqdm
for i in tqdm(range(10000)):
...

لقد كتبت شريط تقدم بسيط:

def bar(total, current, length=10, prefix="", filler="#", space=" ", oncomp="", border="[]", suffix=""):
    if len(border) != 2:
        print("parameter 'border' must include exactly 2 symbols!")
        return None

    print(prefix + border[0] + (filler * int(current / total * length) +
                                      (space * (length - int(current / total * length)))) + border[1], suffix, "\r", end="")
    if total == current:
        if oncomp:
            print(prefix + border[0] + space * int(((length - len(oncomp)) / 2)) +
                  oncomp + space * int(((length - len(oncomp)) / 2)) + border[1], suffix)
        if not oncomp:
            print(prefix + border[0] + (filler * int(current / total * length) +
                                        (space * (length - int(current / total * length)))) + border[1], suffix)

كما ترون ، يحتوي على: طول الشريط ، البادئة واللاحقة ، الحشو ، المساحة ، النص في الشريط على 100 ٪ (oncomp) والحدود

مثال هنا:

from time import sleep, time
start_time = time()
for i in range(10):
    pref = str((i+1) * 10) + "% "
    complete_text = "done in %s sec" % str(round(time() - start_time))
    sleep(1)
    bar(10, i + 1, length=20, prefix=pref, oncomp=complete_text)

في التقدم:

30% [######              ]

في الخارج:

100% [   done in 9 sec   ] 
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top