Python'da stdout için önceki baskının üzerine nasıl yazılır?


113

Aşağıdaki koda sahip olsaydım:

for x in range(10):
     print x

Çıktısını alırdım

1
2
etc..

Yapmak istediğim şey bir satırsonu yazdırmak yerine, önceki değeri değiştirip aynı satırdaki yeni değerin üzerine yazmak istiyorum.



Bir yan not olarak, önceki satır mevcut satırdan daha uzunsa tüm satırı temizleyebilecek yanıtı aldığınızdan emin olun .
Fruit

Yanıtlar:


119

Bir yol, '\r'sonraki satıra geçmeden satırın başına dönmek için satır başı ( ) karakterini kullanmaktır:

for x in range(10):
    print '{0}\r'.format(x),
print

Print ifadesinin sonundaki virgül, bir sonraki satıra geçmemesini söyler. Son print deyimi sonraki satıra ilerler, böylece isteminiz son çıktınızın üzerine yazmaz.

Güncelleme

Python 2 artık EOL olduğuna göre, bir Python 3 cevabı daha mantıklı. Python 3.5 ve öncesi için:

for x in range(10):
    print('{}\r'.format(x), end="")
print()

Python 3.6 ve sonrasında, f dizeleri daha iyi okunur:

for x in range(10):
    print(f'{x}\r', end="")
print()

Bu işe yarıyor, ancak birkaç parçayı anlamıyorum ... '{0}' ve .format
ccwhite1

7
Bu, Python 2.6'da tanıtıldı ve (bana söylendi) Python 3'te dizeleri biçimlendirmenin standart yolu; %Operatör kaldırılmıştır. Temel olarak, tüm dizelerin artık bir biçim yöntemi vardır. Bu durumda, {0}"ilk argüman" anlamına gelir format()(sayma 0'dan başlar).
Mike DeSimone

Yalnızca Windows'a özgü bir yazılım kullanmanız gerekiyorsa ve bir VM çalıştırmak için gerekli işlemlere sahip değilseniz, bu bir seçenek değildir.
Mike DeSimone

2
Ve çapraz terminal olmak istiyorsanız, kullanıcının sahip olduğu terminal re.sub(r'\$<\d+>[/*]?', '', curses.tigetstr('el') or '')için size doğru satır sonuna kadar silme dizesini verecektir. cursesGibi bir şeyle başlatmayı unutmayın curses.setupterm(fd=sys.stdout.fileno())ve sys.stdout.isatty()çıktınızın bir dosyaya yönlendirilmediğinden emin olmak için kullanın . İmleç kontrolü ve renk desteği ile tam bir Python modülü için code.activestate.com/recipes/475116 adresine bakın .
Mike DeSimone

1
@PhilMacKay: Bunu Mac'imde python'da denedim: [3] 'te: "Thing to silmeli \ r" yazdırın,; time.sleep (1); print "-------------- \ r", -------------- Sorununuzun Windows ve onun farklı satır uçları olduğunu düşünüyorum. import curses; curses.setupterm(fd=sys.stdout.fileno()); print(hex(curses.tigetstr('cr')));Şunu deneyin: Satırın başına gitmek için karakter dizisinin onaltılık kodlarını yazdırmalıdır.
Mike DeSimone

107

Buraya Google aracılığıyla geldiğimden ancak Python 3 kullandığım için, işte bunun Python 3'te nasıl çalışacağı:

for x in range(10):
    print("Progress {:2.1%}".format(x / 10), end="\r")

İlgili cevap burada: Bir print ifadesinden sonra yeni satırı nasıl bastırabilirim?


3
Bunu denedim ve çoğunlukla iyi çalışıyor. Tek sorun, bu satırdaki önceki çıktıyı silmemesidir, örneğin: eğer ilk döngü baskınız testingve ikinci döngü baskınız varsa test, ikinci geçişten sonraki çıktı hala olacaktır testing- şimdi @ Nagasaki45'in bunu işaret ettiğini görüyorum
Eric Uldall

15
ipython not defterinde yapmam gerekenler:print("\r", message, end="")
grisaitis

1
Bu harika çalışıyor, satırı silmiyor, ancak aşağıdaki baskıda yeterince beyaz boşluk kullanmak işi yapıyor (zarif olmasa da). Ekleyebileceğim bir yorum, bunun VS Code'un hata ayıklama konsolunda çalışmadığı, ancak terminalde çalıştığıdır.
PhilMacKay

32

@Mike DeSimone cevabı muhtemelen çoğu zaman işe yarayacaktır. Fakat...

for x in ['abc', 1]:
    print '{}\r'.format(x),

-> 1bc

Bunun nedeni, '\r'tek satırın başına geri dönmesi ancak çıktıyı temizlememesidir.

DÜZENLEME: Daha iyi çözüm (aşağıdaki eski teklifimden)

POSIX desteği sizin için yeterliyse, aşağıdakiler mevcut satırı temizler ve imleci başında bırakır:

print '\x1b[2K\r',

Terminal hattını temizlemek için ANSI çıkış kodunu kullanır. Wikipedia'da ve bu harika konuşmada daha fazla bilgi bulunabilir .

Eski cevap

Bulduğum (o kadar iyi değil) çözüm şuna benziyor:

last_x = ''
for x in ['abc', 1]:
    print ' ' * len(str(last_x)) + '\r',
    print '{}\r'.format(x),
    last_x = x

-> 1

Bir avantajı, pencerelerde de çalışacak olmasıdır.


1
Düzgün çalışan 'eski cevap'tan bir işlev yaptım (Windows'ta bile),
cevabıma

25

Bu konuyu ziyaret etmeden önce aynı soruyu sordum. Benim için sys.stdout.write sadece tamponu düzgün bir şekilde temizlersem çalıştı, yani

for x in range(10):
    sys.stdout.write('\r'+str(x))
    sys.stdout.flush()

Boşaltma olmadan, sonuç yalnızca komut dosyasının sonunda yazdırılır


Dizenin geri kalanını, stringvar.ljust(10,' ')değişken uzunluklu dizelerde olduğu gibi boşluklarla doldurmak da iyi bir fikirdir .
Annarfych

@chris, Don ve diğerleri. bu Python 2, diğer cevapların çoğu Python 3'tür. Herkes artık Python 3 kullanıyor olmalı; Python 2, 2020'de kullanım ömrünün sonu.
smci

18

Yeni satırı bastırın ve yazdırın \r.

print 1,
print '\r2'

veya standart çıktıya yazın:

sys.stdout.write('1')
sys.stdout.write('\r2')

9

Bunu dene:

import time
while True:
    print("Hi ", end="\r")
    time.sleep(1)
    print("Bob", end="\r")
    time.sleep(1)

Benim için çalıştı. end="\r"Bölüm önceki satırın üzerine yapıyor.

UYARI!

Eğer çıktısını olursa hi, o zaman çıktısını hellokullanarak \relde edersiniz, hilloçıkış önceki iki harf üzerine yazdım çünkü. hiBoşluklarla yazdırırsanız (burada gösterilmez), çıktı alacaktır hi. Bunu düzeltmek için, kullanarak boşlukları yazdırın \r.


1
Bu benim için çalışmıyor. Bu kodla başa çıktım, ama çıktım Hi BobHi BobHi BobHi BobHi Bob. Python 3.7.1
PaulMag

1
Ancak Rubixred'in cevabı işe yaradı. Tuhaf. Bana aynı yöntem gibi görünüyorlar. Gördüğüm tek fark, sondan \rçok başlangıçta olmasıdır.
PaulMag

7

IPython için çalışmak için bu sayfadaki çözümlerin hiçbirini bulamadım , ancak @ Mike-Desimone'nin çözümündeki küçük bir değişiklik işi yaptı: satırı satır başı ile sonlandırmak yerine satıra satır başı ile başlayın :

for x in range(10):
    print '\r{0}'.format(x),

Ek olarak, bu yaklaşım ikinci print ifadesini gerektirmez.


PyDev konsolunda bu bile çalışmıyor, print () 'in yakın parantezinden sonra virgül gelmiyor.
Noumenon

benim için işe yaramadı, sadece işlem bittiğinde nihai sonucu (ör: "İndirme ilerlemesi% 100") yazar.
Alexandre

2
@Alexandre IPython'da veya halefi Jupyter'da sorunsuz çalışıyor. Tamponu temizlemeniz gerekiyor. stackoverflow.com/questions/17343688/…
Mart Ho

7
for x in range(10):
    time.sleep(0.5) # shows how its working
    print("\r {}".format(x), end="")

time.sleep (0.5), önceki çıktının nasıl silindiğini ve yeni çıktının "\ r" yazdırıldığını göstermek içindir, yazdırma mesajının başlangıcında, yeni çıktıdan önce önceki çıktıyı silecektir.


7

Bu, Windows ve python 3.6'da çalışır

import time
for x in range(10):
    time.sleep(0.5)
    print(str(x)+'\r',end='')

5

Kabul edilen cevap mükemmel değil . İlk basılan satır orada kalacak ve ikinci baskınız yeni satırın tamamını kapsamıyorsa, çöp metinle karşılaşacaksınız.

Sorunu göstermek için bu kodu bir betik olarak kaydedin ve çalıştırın (veya sadece bir göz atın):

import time

n = 100
for i in range(100):
    for j in range(100):
        print("Progress {:2.1%}".format(j / 100), end="\r")
        time.sleep(0.01)
    print("Progress {:2.1%}".format(i / 100))

Çıktı şunun gibi görünecek:

Progress 0.0%%
Progress 1.0%%
Progress 2.0%%
Progress 3.0%%

Benim için işe yarayan şey, kalıcı bir baskı bırakmadan önce satırı temizlemek. Özel probleminize uyum sağlamaktan çekinmeyin:

import time

ERASE_LINE = '\x1b[2K' # erase line command
n = 100
for i in range(100):
    for j in range(100):
        print("Progress {:2.1%}".format(j / 100), end="\r")
        time.sleep(0.01)
    print(ERASE_LINE + "Progress {:2.1%}".format(i / 100)) # clear the line first

Ve şimdi beklendiği gibi yazdırıyor:

Progress 0.0%
Progress 1.0%
Progress 2.0%
Progress 3.0%

5

İşte @ Nagasaki45'in cevabının daha temiz, daha "tak ve çalıştır" versiyonu. Buradaki diğer birçok cevabın aksine, farklı uzunluktaki dizelerle düzgün çalışıyor. Bunu, yazdırılan son satırın uzunluğu kadar boşluk bırakarak satırı temizleyerek gerçekleştirir. Windows üzerinde de çalışacak.

def print_statusline(msg: str):
    last_msg_length = len(print_statusline.last_msg) if hasattr(print_statusline, 'last_msg') else 0
    print(' ' * last_msg_length, end='\r')
    print(msg, end='\r')
    sys.stdout.flush()  # Some say they needed this, I didn't.
    print_statusline.last_msg = msg

kullanım

Basitçe şu şekilde kullanın:

for msg in ["Initializing...", "Initialization successful!"]:
    print_statusline(msg)
    time.sleep(1)

Bu küçük test, farklı uzunluklarda bile hatların düzgün bir şekilde temizlendiğini gösterir:

for i in range(9, 0, -1):
    print_statusline("{}".format(i) * i)
    time.sleep(0.5)

5
Bu harika bir çözüm çünkü sadece rastgele sayıda beyaz boşluk yazdırmadan önceki çıktıyı tam uzunluğuna kadar zarif bir şekilde temizliyor (daha önce başvurduğum şey buydu!) Teşekkürler
Toby Petty

2

Hiç kimsenin geri alma karakterini kullanmamasına biraz şaşırdım. İşte onu kullanan biri.

import sys
import time

secs = 1000

while True:
    time.sleep(1)  #wait for a full second to pass before assigning a second
    secs += 1  #acknowledge a second has passed

    sys.stdout.write(str(secs))

    for i in range(len(str(secs))):
        sys.stdout.write('\b')

bu yöntemi kullandıktan sonra yıkadığınızdan emin olun, aksi takdirde ekrana yazdırılan hiçbir şey elde edemeyebilirsiniz. sys.stdout.flush()
Gabriel Fair

2

(Python3) Bu benim için çalıştı. Sadece \ 010 kullanırsanız, o zaman karakter bırakacaktır, bu yüzden orada olanın üzerine yazdığından emin olmak için biraz ince ayar yaptım. Bu ayrıca, ilk baskı öğesinden önce bir şey almanıza ve yalnızca öğenin uzunluğunu kaldırmanıza olanak tanır.

print("Here are some strings: ", end="")
items = ["abcd", "abcdef", "defqrs", "lmnop", "xyz"]
for item in items:
    print(item, end="")
    for i in range(len(item)): # only moving back the length of the item
        print("\010 \010", end="") # the trick!
        time.sleep(0.2) # so you can see what it's doing

2

Önceki cevaplara göre bir cevap daha.

Pbar.py içeriği: import sys, shutil, datetime

last_line_is_progress_bar=False


def print2(print_string):
    global last_line_is_progress_bar
    if last_line_is_progress_bar:
        _delete_last_line()
        last_line_is_progress_bar=False
    print(print_string)


def _delete_last_line():
    sys.stdout.write('\b\b\r')
    sys.stdout.write(' '*shutil.get_terminal_size((80, 20)).columns)
    sys.stdout.write('\b\r')
    sys.stdout.flush()


def update_progress_bar(current, total):
    global last_line_is_progress_bar
    last_line_is_progress_bar=True

    completed_percentage = round(current / (total / 100))
    current_time=datetime.datetime.now().strftime('%m/%d/%Y-%H:%M:%S')
    overhead_length = len(current_time+str(current))+13
    console_width = shutil.get_terminal_size((80, 20)).columns - overhead_length
    completed_width = round(console_width * completed_percentage / 100)
    not_completed_width = console_width - completed_width
    sys.stdout.write('\b\b\r')

    sys.stdout.write('{}> [{}{}] {} - {}% '.format(current_time, '#'*completed_width, '-'*not_completed_width, current,
                                        completed_percentage),)
    sys.stdout.flush()

Komut dosyası kullanımı:

import time
from pbar import update_progress_bar, print2


update_progress_bar(45,200)
time.sleep(1)

update_progress_bar(70,200)
time.sleep(1)

update_progress_bar(100,200)
time.sleep(1)


update_progress_bar(130,200)
time.sleep(1)

print2('some text that will re-place current progress bar')
time.sleep(1)

update_progress_bar(111,200)
time.sleep(1)

print('\n') # without \n next line will be attached to the end of the progress bar
print('built in print function that will push progress bar one line up')
time.sleep(1)

update_progress_bar(111,200)
time.sleep(1)

1

İşte benim çözümüm! Windows 10, Python 3.7.1

Bu kodun neden çalıştığından emin değilim, ancak orijinal satırı tamamen siliyor. Bunu önceki cevaplardan derledim. Diğer cevaplar sadece satırı başa döndürürdü, ancak daha sonra daha kısa bir satırınız olsaydı, hellodönüşler gibi dağınık görünürdü byelo.

import sys
#include ctypes if you're on Windows
import ctypes
kernel32 = ctypes.windll.kernel32
kernel32.SetConsoleMode(kernel32.GetStdHandle(-11), 7)
#end ctypes

def clearline(msg):
    CURSOR_UP_ONE = '\033[K'
    ERASE_LINE = '\x1b[2K'
    sys.stdout.write(CURSOR_UP_ONE)
    sys.stdout.write(ERASE_LINE+'\r')
    print(msg, end='\r')

#example
ig_usernames = ['beyonce','selenagomez']
for name in ig_usernames:
    clearline("SCRAPING COMPLETE: "+ name)

Çıktı - Her satır, herhangi bir eski metin gösterilmeden yeniden yazılacaktır:

SCRAPING COMPLETE: selenagomez

Sonraki satır (tamamen aynı satıra yeniden yazılmıştır):

SCRAPING COMPLETE: beyonce

0

Tüm satırın üzerine yazmak daha iyidir, aksi takdirde yeni satır daha kısaysa yeni satır eskilerle karışacaktır.

import time, os
for s in ['overwrite!', 'the!', 'whole!', 'line!']:
    print(s.ljust(os.get_terminal_size().columns - 1), end="\r")
    time.sleep(1)

columns - 1Windows'ta kullanmak zorundaydı .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.