Вивести в той самий рядок, перезаписавши попередній вивід?


97

Я пишу завантажувач FTP. Частина коду приблизно така:

ftp.retrbinary("RETR " + file_name, process)

Я викликаю процес функції для обробки зворотного виклику:

def process(data):
    print os.path.getsize(file_name)/1024, 'KB / ', size, 'KB downloaded!'
    file.write(data)

і висновок приблизно такий:

1784  KB / KB 1829 downloaded!
1788  KB / KB 1829 downloaded!
etc...   

але я хочу, щоб він надрукував цей рядок і наступного разу передрукував / оновив його, щоб він показав його лише один раз, і я побачу хід цього завантаження.

Як це можна зробити?



Можливий дублікат панелі прогресу тексту в консолі
Олексій

Відповіді:


189

Ось код для Python 3.x:

print(os.path.getsize(file_name)/1024+'KB / '+size+' KB downloaded!', end='\r')

end=Ключове слово , що робить роботу тут - за замовчуванням, print()закінчується в нового рядка ( \n) характер, але це може бути замінений на інший рядку. У цьому випадку закінчення рядка поверненням каретки замість цього повертає курсор на початок поточного рядка. Таким чином, немає необхідності імпортувати sysмодуль для такого простого використання. print()насправді має ряд аргументів ключових слів, які можна використовувати для значного спрощення коду.

Щоб використовувати той самий код на Python 2.6+, поставте такий рядок у верхній частині файлу:

from __future__ import print_function

6
Зверніть увагу , що функція друку також може бути використана в Пітоні 2.6+, додавши наступний імпорт в верхній частині файлу: from __future__ import print_function.
janin

12
у python <3.0 кома в кінці висловлення запобіжить "\ n": print "foo",Однак вам все одно потрібно змити після цього, щоб побачити зміни:sys.stdout.flush()
Тобіас Домхан

31
Я виявив, що мені потрібно включити \rна початку рядка, і end=''замість цього встановити, щоб це працювало. Я не думаю, що моєму терміналу подобається, коли я закінчую\r
Jezzamon

2
У всіх поточних випусках Python 3 ви можете додати flush=Trueдо print()функції, щоб переконатись, що буфер очищений (стандартний буфер рядка буде змиватися лише тоді, коли \nбуде записано новий рядок).
Мартін Пітерс

4
У блокноті jupyter, використовуючи \rспочатку, і end=''працював найкраще та гладкіше. Використовуючи flush=Trueз \rкінцем, якщо рядок end='\r'також працював, але не був рівним, стирав лінію та її подачу лінії.
Dave X

40

Якщо все, що ви хочете зробити, це змінити один рядок, використовуйте \r. \rозначає повернення каретки. Його ефект полягає лише в тому, щоб повернути каретку назад на початок поточного рядка. Це нічого не стирає. Подібним чином \bможе використовуватися для повернення одного символу назад. (деякі термінали можуть не підтримувати всі ці функції)

import sys

def process(data):
    size_str = os.path.getsize(file_name)/1024, 'KB / ', size, 'KB downloaded!'
    sys.stdout.write('%s\r' % size_str)
    sys.stdout.flush()
    file.write(data)

1
я б додав, що \rозначає повернення каретки. його ефект полягає лише у поверненні каретки на початок поточного рядка. це нічого не стирає. аналогічно, \bможе використовуватися для повернення одного символу назад. (деякі термінали можуть не підтримувати всіх цих функцій)
Адріен Пліссон,

sys.stdout.write('%s\r', size_str')Я думаю, ви мали на увазі, sys.stdout.write('%s\r' % size_str)але це не працює.
Крістіан

@Adrien: Круто, додав це. @Kristian: Дякую, оновив це, було досить пізно.
Sam Dolan

Також зверніть увагу, що ви все ще можете використовувати printзамість того, sys.stdout.writeякщо вам більше подобається: print size_str + "\r",працює чудово. У ,кінці оператора print друкується рядок; sys.stdout.flush()все ще потрібен
Джефф

19

Погляньте на документацію модуля curses та модуль curses HOWTO .

Дійсно базовий приклад:

import time
import curses

stdscr = curses.initscr()

stdscr.addstr(0, 0, "Hello")
stdscr.refresh()

time.sleep(1)

stdscr.addstr(0, 0, "World! (with curses)")
stdscr.refresh()

10
на жаль, прокляття доступні лише на Unix. ОП не повідомив нам, на яку операційну систему націлений його додаток ...
Адріен Пліссон,

Я настільки звик працювати під Linux, що навіть не помітив попередження про те, що модуль призначений лише для UNIX у документах модуля .. Дякую, що вказав на це, @Adrien.
Андреа Спадаччіні

3
@AdrienPlisson, я знаю, що це питання було зроблено багато років тому, але насправді ви можете отримати Прокляття на Windows: lfd.uci.edu/~gohlke/pythonlibs/#curses
Cold Diamondz

Коли я вставив це в свій інтерпретатор Python, мій термінал став fubar. Вихід з перекладача не допоміг. WTF ?!
allyourcode

Використовуйте clrtoeolдля , коли друга лінія коротше , ніж перший.
Serge Stroobandt

9

Ось мій маленький клас, який може передрукувати блоки тексту. Він належним чином очищає попередній текст, щоб ви могли замінити старий текст на коротший новий текст, не створюючи безладу.

import re, sys

class Reprinter:
    def __init__(self):
        self.text = ''

    def moveup(self, lines):
        for _ in range(lines):
            sys.stdout.write("\x1b[A")

    def reprint(self, text):
        # Clear previous text by overwritig non-spaces with spaces
        self.moveup(self.text.count("\n"))
        sys.stdout.write(re.sub(r"[^\s]", " ", self.text))

        # Print new text
        lines = min(self.text.count("\n"), text.count("\n"))
        self.moveup(lines)
        sys.stdout.write(text)
        self.text = text

reprinter = Reprinter()

reprinter.reprint("Foobar\nBazbar")
reprinter.reprint("Foo\nbar")

2
Це не буде працювати в Windows до Windows 10, оскільки Windows 10 є першим вікном, яке підтримує ці символи керування en.wikipedia.org/wiki/ANSI_escape_code
user136036

8

Я виявив, що для простого оператора друку в python 2.7 просто поставте кому в кінці після вашого '\r'.

print os.path.getsize(file_name)/1024, 'KB / ', size, 'KB downloaded!\r',

Це коротше, ніж інші рішення, не пов'язані з python 3, але також складніше в обслуговуванні.


1
Python 2.7.10, і він нічого не друкує. Можливо, ви можете скомпілювати його в Інтернеті та надіслати нам посилання, щоб побачити, як це працює ...?
Шуго Макісіма

5

Ви можете просто додати '\ r' в кінці рядка плюс кома в кінці функції друку. Наприклад:

print(os.path.getsize(file_name)/1024+'KB / '+size+' KB downloaded!\r'),

1
Це для python 3? Якщо так , то з по замовчуванням endнабір параметрів для \nтак у друку (...)KB downloaded!\r\n. Я помиляюся?
SR

Використання end = '\r'замість цього вирішує проблему в Python 3.
Abhimanyu Pallavi Sudhir

4

Я використовую spyder 3.3.1 - windows 7 - python 3.6, хоча змив може не знадобитися. на основі цього повідомлення - https://github.com/spyder-ide/spyder/issues/3437

   #works in spyder ipython console - \r at start of string , end=""
import time
import sys
    for i in range(20):
        time.sleep(0.5)
        print(f"\rnumber{i}",end="")
        sys.stdout.flush()

1

щоб перезаписати попередній рядок у python, все, що вам потрібно, це додати end = '\ r' до функції друку, протестуйте цей приклад:

import time
for j in range(1,5):
   print('waiting : '+j, end='\r')
   time.sleep(1)
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.