พิมพ์ไปที่บรรทัดเดียวกันแล้วขึ้นบรรทัดใหม่ไม่ใช่เหรอ?


89

โดยทั่วไปฉันต้องการทำสิ่งที่ตรงกันข้ามกับสิ่งที่ผู้ชายคนนี้ทำ ... ฮิฮิ

Python Script: พิมพ์บรรทัดใหม่ทุกครั้งเพื่อเชลล์แทนที่จะอัปเดตบรรทัดที่มีอยู่

ฉันมีโปรแกรมที่บอกฉันว่ามันไปได้ไกลแค่ไหน

for i in some_list:
    #do a bunch of stuff.
    print i/len(some_list)*100," percent complete"

ดังนั้นถ้า len (some_list) เป็น 50 ฉันจะพิมพ์บรรทัดสุดท้ายได้ 50 ครั้ง ฉันต้องการพิมพ์หนึ่งบรรทัดและอัปเดตบรรทัดนั้นต่อไป ฉันรู้ว่านี่อาจเป็นคำถามที่แย่ที่สุดที่คุณจะอ่านทั้งวัน ฉันไม่สามารถหาคำสี่คำที่ฉันต้องใส่ใน Google เพื่อให้ได้คำตอบ

อัพเดท! ฉันลองทำตามคำแนะนำของ mvds ซึ่งคิดว่าถูกต้อง รหัสใหม่

print percent_complete,"           \r",

เปอร์เซ็นต์ที่สมบูรณ์เป็นเพียงสตริง (ฉันเขียนบทคัดย่อครั้งแรกตอนนี้ฉันพยายามจะเป็นตัวอักษร) ผลลัพธ์ตอนนี้คือรันโปรแกรมไม่พิมพ์อะไรเลยจนกว่าโปรแกรมจะจบลงจากนั้นพิมพ์ "เสร็จสมบูรณ์ 100 เปอร์เซ็นต์" ในบรรทัดเดียว

หากไม่มีการคืนแคร่ (แต่มีเครื่องหมายจุลภาคครึ่งหนึ่งของคำแนะนำของ mvds) จะไม่พิมพ์อะไรเลยจนกว่าจะสิ้นสุด แล้วพิมพ์:

0 percent complete     2 percent complete     3 percent complete     4 percent complete    

และอื่น ๆ ตอนนี้ปัญหาใหม่คือด้วยลูกน้ำมันจะไม่พิมพ์จนกว่าโปรแกรมจะเสร็จสิ้น

ด้วยการกลับแคร่และไม่มีลูกน้ำมันจะทำงานเหมือนกับไม่มีทั้งคู่


คุณอาจต้องการตรวจสอบด้วยsys.stdout.isatty()เพื่อไม่ให้คายสิ่งเหล่านี้ออกมาเมื่อไม่ได้ทำงานในเทอร์มินัล
mvds

ฉันกำลังเรียกใช้สิ่งนี้จากอาคารผู้โดยสาร ... คิดว่าดี ฉันแน่ใจว่าฉันต้องการสิ่งนั้นในบางจุด
chriscauley

1
พื้นหลังคือ btw ซึ่งในหลายภาษา \ n (ซึ่งปัจจุบันเราละไว้) ทำหน้าที่เป็นสัญญาณโดยปริยายเพื่อล้างไปยัง stdout มิฉะนั้นหลายคนจะสับสน
mvds

คำตอบ:


86

เรียกว่าการกลับรถหรือ \r

ใช้

print i/len(some_list)*100," percent complete         \r",

ลูกน้ำป้องกันไม่ให้พิมพ์ขึ้นบรรทัดใหม่ (และช่องว่างจะทำให้บรรทัดชัดเจนจากเอาต์พุตก่อนหน้า)

นอกจากนี้อย่าลืมปิดท้ายด้วย a print ""เพื่อรับการขึ้นบรรทัดใหม่อย่างน้อยที่สุด!


12
ตรวจสอบให้แน่ใจว่าคุณกำลังพิมพ์ข้อมูลจำนวนเท่ากัน (หรือมากกว่าการพิมพ์ครั้งก่อน ๆ ) ลงในบรรทัดเสมอมิฉะนั้นคุณจะจบลงด้วยการตรึงในตอนท้าย
Nicholas Knight

ใกล้แล้ว ... ฉันจะอัปเดตคำถามพร้อมผลลัพธ์ของสิ่งนี้
chriscauley

2
@dustynachos: เดี๋ยวก่อนลืมเรื่องริ้วรอยนั้นไป ดูคำถาม Python Output Buffering: stackoverflow.com/questions/107705/python-output-buffering
Nicholas Knight

1
@dustynachos: (หรือใช้ sys.stdout.flush () หลังจากการเรียกพิมพ์แต่ละครั้งซึ่งอาจดีกว่าถ้าคุณไม่สนใจเกี่ยวกับการบัฟเฟอร์เอาต์พุตสำหรับส่วนที่เหลือของโปรแกรมของคุณ)
Nicholas Knight

2
สิ่งนี้ไม่ได้ผลสำหรับฉัน ฉันได้ลองหลายครั้งแล้วและมันไม่เคยได้ผลสำหรับฉัน ฉันใช้ iterm2 บนเครื่อง mac แต่ฉันใช้งานในเซิร์ฟเวอร์ linux เกือบตลอดเวลา ฉันไม่เคยพบวิธีการทำเช่นนี้ที่ได้ผลจริง
bgenchel

33

จาก python 3.x คุณสามารถทำได้:

print('bla bla', end='')

(ซึ่งสามารถใช้ได้ใน Python 2.6 หรือ 2.7 โดยวางไว้from __future__ import print_functionที่ด้านบนของสคริปต์ / โมดูลของคุณ)

ตัวอย่างแถบความคืบหน้าของคอนโซล Python:

import time

# status generator
def range_with_status(total):
    """ iterate from 0 to total and show progress in console """
    n=0
    while n<total:
        done = '#'*(n+1)
        todo = '-'*(total-n-1)
        s = '<{0}>'.format(done+todo)
        if not todo:
            s+='\n'        
        if n>0:
            s = '\r'+s
        print(s, end='')
        yield n
        n+=1

# example for use of status generator
for i in range_with_status(10):
    time.sleep(0.1)

\ r ดูเหมือนจะเพิ่มบรรทัดใหม่ด้วย
fccoelho

3
สิ่งนี้จะกำจัดขึ้นบรรทัดใหม่ แต่ไม่อนุญาตให้เขียนทับซึ่งฉันคิดว่าเป็นสิ่งที่ผู้เขียนต้องการ
bgenchel

1
@bgenchel ใช้กับ '\ r' (ตามตัวอย่างโค้ด) มันทำตามที่ OP ต้องการ
Milo Wielondek

33

สำหรับฉันสิ่งที่ได้ผลคือคำสั่งผสมของคำตอบของ Remi และ siriusd:

from __future__ import print_function
import sys

print(str, end='\r')
sys.stdout.flush()

ล้าสมัย .. เนื่องจาก Python 3.8.5 สำหรับฉันเท่านั้นที่ใช้งานได้: print ("some string", end = '\ r')
rroger

23

ในหลาม 3.3 sys.stdout.flush()หรือสูงกว่าคุณไม่จำเป็นต้อง print(string, end='', flush=True)ได้ผล

ดังนั้น

print('foo', end='')
print('\rbar', end='', flush=True)

จะเขียนทับ 'foo' ด้วย 'bar'


2
ใช้งานได้หากข้อความที่พิมพ์ลงท้ายด้วยไฟล์"\r".
bli

13

สำหรับคอนโซลคุณอาจต้องการ

sys.stdout.flush()

เพื่อบังคับให้อัปเดต ฉันคิดว่าการใช้,ในการพิมพ์จะบล็อก stdout จากการล้างและอย่างใดก็ไม่อัปเดต


Terminator รีเฟรชบรรทัดทุกๆ 30 วินาทีเมื่อใช้ print ("... ", end = '\ r') ให้ฉันเว้นแต่ฉันจะรันคำสั่งนี้ทันทีหลังจากคำสั่งพิมพ์ ขอบคุณ
Bryce Guinta

4

เกมล่าช้า - แต่เนื่องจากไม่มีคำตอบใดที่ใช้ได้ผลสำหรับฉัน (ฉันไม่ได้ลองทั้งหมด) และฉันได้รับคำตอบนี้มากกว่าหนึ่งครั้งในการค้นหาของฉัน ... ใน python 3 วิธีนี้ค่อนข้างสวย และฉันเชื่อว่าทำในสิ่งที่ผู้เขียนกำลังมองหาอย่างแน่นอนโดยจะอัปเดตคำสั่งเดียวในบรรทัดเดียวกัน หมายเหตุคุณอาจต้องทำบางอย่างเป็นพิเศษถ้าเส้นหดแทนที่จะโตขึ้น (เช่นอาจทำให้สตริงมีความยาวคงที่โดยมีช่องว่างด้านท้าย)

if __name__ == '__main__':
    for i in range(100):
        print("", end=f"\rPercentComplete: {i} %")
        time.sleep(0.2)

1
ตัวเลือกที่ง่ายและสะอาดที่สุดสำหรับ python => 3.6
DaveR

3

สิ่งนี้ใช้ได้กับฉันแฮ็กหนึ่งครั้งเพื่อดูว่าเป็นไปได้หรือไม่ แต่ไม่เคยใช้จริงในโปรแกรมของฉัน (GUI ดีกว่ามาก):

import time
f = '%4i %%'
len_to_clear = len(f)+1
clear = '\x08'* len_to_clear
print 'Progress in percent:'+' '*(len_to_clear),
for i in range(123):
    print clear+f % (i*100//123),
    time.sleep(0.4)
raw_input('\nDone')

2
import time
import sys


def update_pct(w_str):
    w_str = str(w_str)
    sys.stdout.write("\b" * len(w_str))
    sys.stdout.write(" " * len(w_str))
    sys.stdout.write("\b" * len(w_str))
    sys.stdout.write(w_str)
    sys.stdout.flush()

for pct in range(0, 101):
    update_pct("{n}%".format(n=str(pct)))
    time.sleep(0.1)

\bจะย้ายตำแหน่งของเคอร์เซอร์ไปข้างหลังหนึ่งช่อง
ดังนั้นเราจึงเลื่อนมันกลับไปที่จุดเริ่มต้นของบรรทัด
จากนั้นเราจะเขียนช่องว่างเพื่อล้างบรรทัดปัจจุบัน - ในขณะที่เราเขียนช่องว่างเคอร์เซอร์จะเลื่อนไปข้างหน้า / ขวาทีละช่อง
ดังนั้นเราจึงมี เพื่อย้ายเคอร์เซอร์กลับไปที่จุดเริ่มต้นของบรรทัดก่อนที่เราจะเขียนข้อมูลใหม่

ทดสอบบน Windows cmd โดยใช้ Python 2.7


1

ลองทำดังนี้:

for i in some_list:
    #do a bunch of stuff.
    print i/len(some_list)*100," percent complete",

(มีเครื่องหมายจุลภาคต่อท้าย)


นี่เป็นเพียงการต่อท้ายข้อความใหม่กับข้อความเก่า (ใช้งานได้คล้ายกัน แต่น่าเกลียด)
chriscauley

1

หากคุณใช้ Spyder บรรทัดจะพิมพ์อย่างต่อเนื่องกับโซลูชันก่อนหน้านี้ทั้งหมด วิธีหลีกเลี่ยงการใช้:

for i in range(1000):
    print('\r' + str(round(i/len(df)*100,1)) + '% complete', end='')
    sys.stdout.flush()

นี่เป็นโซลูชันเดียวที่ใช้งานได้สำหรับฉัน (Python 3.8, Windows, PyCharm)
z33k


0

ตามคำตอบของ RemiสำหรับการPython 2.7+ใช้งานสิ่งนี้:

from __future__ import print_function
import time

# status generator
def range_with_status(total):
    """ iterate from 0 to total and show progress in console """
    import sys
    n = 0
    while n < total:
        done = '#' * (n + 1)
        todo = '-' * (total - n - 1)
        s = '<{0}>'.format(done + todo)
        if not todo:
            s += '\n'
        if n > 0:
            s = '\r' + s
        print(s, end='\r')
        sys.stdout.flush()
        yield n
        n += 1


# example for use of status generator
for i in range_with_status(50):
    time.sleep(0.2)

0

สำหรับPython 3.6+และที่listไม่ใช่แค่ints เช่นเดียวกับการใช้ความกว้างทั้งหมดของหน้าต่างคอนโซลของคุณและไม่ข้ามไปยังบรรทัดใหม่คุณสามารถใช้สิ่งต่อไปนี้:

หมายเหตุ: โปรดทราบว่าฟังก์ชันget_console_with()นี้จะใช้งานได้กับระบบที่ใช้ Linux เท่านั้นดังนั้นคุณต้องเขียนใหม่เพื่อให้ทำงานบน Windows ได้

import os
import time

def get_console_width():
    """Returns the width of console.

    NOTE: The below implementation works only on Linux-based operating systems.
    If you wish to use it on another OS, please make sure to modify it appropriately.
    """
    return int(os.popen('stty size', 'r').read().split()[1])


def range_with_progress(list_of_elements):
    """Iterate through list with a progress bar shown in console."""

    # Get the total number of elements of the given list.
    total = len(list_of_elements)
    # Get the width of currently used console. Subtract 2 from the value for the
    # edge characters "[" and "]"
    max_width = get_console_width() - 2
    # Start iterating over the list.
    for index, element in enumerate(list_of_elements):
        # Compute how many characters should be printed as "done". It is simply
        # a percentage of work done multiplied by the width of the console. That
        # is: if we're on element 50 out of 100, that means we're 50% done, or
        # 0.5, and we should mark half of the entire console as "done".
        done = int(index / total * max_width)
        # Whatever is left, should be printed as "unfinished"
        remaining = max_width - done
        # Print to the console.
        print(f'[{done * "#"}{remaining * "."}]', end='\r')
        # yield the element to work with it
        yield element
    # Finally, print the full line. If you wish, you can also print whitespace
    # so that the progress bar disappears once you are done. In that case do not
    # forget to add the "end" parameter to print function.
    print(f'[{max_width * "#"}]')


if __name__ == '__main__':
    list_of_elements = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j']
    for e in range_with_progress(list_of_elements):
        time.sleep(0.2)


0

หากคุณใช้ Python 3 สิ่งนี้เหมาะสำหรับคุณและใช้งานได้จริง

print(value , sep='',end ='', file = sys.stdout , flush = False)

0

เพิ่งคิดออกด้วยตัวเองเพื่อแสดงการนับถอยหลัง แต่มันก็ใช้ได้ผลเป็นเปอร์เซ็นต์ด้วย

import time
#Number of seconds to wait
i=15
#Until seconds has reached zero
while i > -1:
    #Ensure string overwrites the previous line by adding spaces at end
    print("\r{} seconds left.   ".format(i),end='')
        time.sleep(1)
        i-=1
    print("") #Adds newline after it's done

ตราบใดที่สิ่งที่ตามหลัง '/ r' มีความยาวเท่ากันหรือยาวกว่า (รวมถึงช่องว่าง) กว่าสตริงก่อนหน้านี้ก็จะเขียนทับในบรรทัดเดียวกัน ตรวจสอบให้แน่ใจว่าคุณใส่ end = '' มิฉะนั้นจะพิมพ์ไปยังบรรทัดใหม่ หวังว่าจะช่วยได้!


0

สำหรับวัตถุ "pega" ที่ให้ StartRunning (), StopRunning (), boolean getIsRunning () และจำนวนเต็ม getProgress100 () ที่ส่งคืนค่าในช่วง 0 ถึง 100 ซึ่งจะให้แถบความคืบหน้าของข้อความขณะรัน ...

now = time.time()
timeout = now + 30.0
last_progress = -1

pega.StartRunning()

while now < timeout and pega.getIsRunning():
    time.sleep(0.5)
    now = time.time()

    progress = pega.getTubProgress100()
    if progress != last_progress:
        print('\r'+'='*progress+'-'*(100-progress)+' ' + str(progress) + "% ", end='', flush=True)
        last_progress = progress

pega.StopRunning()

progress = pega.getTubProgress100()
print('\r'+'='*progress+'-'*(100-progress)+' ' + str(progress) + "% ", flush=True)

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.