3

I would like to understand how to reprint multiple lines in Python 3.5.

This is an example of a script where I would like to refresh the printed statement in place.

import random
import time

a = 0
while True:
    statement = """
    Line {}
    Line {}
    Line {}
    Value = {}
    """.format(random.random(), random.random(), random.random(), a)
    print(statement, end='\r')
    time.sleep(1)
    a += 1

What I am trying to do is have:

Line 1
Line 2
Line 3
Value = 1

Write on top of / update / refresh:

Line 1
Line 2
Line 3
Value = 0

The values of each line will change each time. This is effectively giving me a status update of each Line.

I saw another question from 5 years ago however with the addition of the end argument in Python 3+ print function, I am hoping that there is a much simpler solution.

Greg
  • 8,175
  • 16
  • 72
  • 125
  • 1
    Not sure what you are trying to do? Please provide a sample console output – TheLazyScripter Aug 29 '16 at 12:17
  • Updated, hopefully it is clearer now, if not please let me know – Greg Aug 29 '16 at 12:21
  • so its actually a single line you want to update ? – Ma0 Aug 29 '16 at 12:22
  • I am trying to update all lines in the statement – Greg Aug 29 '16 at 12:25
  • Ok so you're trying to only reprint a line that has changed, Dynamic screen refresh?? Using the default python IDE, this is not possible to my knoledge. There are ways to fake it buy it won't look as fluid. – TheLazyScripter Aug 29 '16 at 12:25
  • but the first three lines are not changing.. #buffled – Ma0 Aug 29 '16 at 12:26
  • @Ev.Kounis I've updated the example to demonstrate the changing nature of each line. – Greg Aug 29 '16 at 12:30
  • In what way did you imagine `end` would help? I am a bit lost how that got a mention in your question and how oil thought it would work. – jwpfox Aug 29 '16 at 12:30
  • @jwpfox I tried end = '\r' * 4 however it did not update the whole statement, only reprinted beginning with the last line. – Greg Aug 29 '16 at 12:32
  • Yes. So how did you think it would help you do what you wanted to do? I am not being snarky I have to assume I am missing something you are trying to tell us that is passing me by. What you experienced with `\r` is expected behaviour but you seem to have expected (hoped?) for something different? Sorry, I am lost. – jwpfox Aug 29 '16 at 12:35
  • `statement` has a height of 4 lines. I want to reprint the value of `statement` again, inplace. So for example, a carriage return to the start of statement would work perfectly. Unfortunately `print(statement, end='\r' * 4)` did not take me back to the start of `statement`, only start of the last line. – Greg Aug 29 '16 at 12:37
  • Check this out `https://docs.python.org/2/howto/curses.html` -- I think you want some thing like `ncurses`. – g-217 Aug 29 '16 at 12:51
  • Can't by-pass delimiter if used before. On python shell `\r` not work, use `print(statement, end="\n\n")` add a blank line for ending. – dsgdfg Aug 29 '16 at 12:52

3 Answers3

3

If you want to clear the screen each time you call print(), so that it appears the print is overwritten each time, you can use clear in unix or cls in windows, for example:

import subprocess
a = 0
while True:
    print(a)
    a += 1
    subprocess.call("clear")
Chris_Rands
  • 38,994
  • 14
  • 83
  • 119
  • This works only if he is working in the terminal. What if he is using the IDLE or some other interpreter? – TheLazyScripter Aug 29 '16 at 12:51
  • This solution is not portable – BPL Aug 29 '16 at 12:59
  • Yes @BPL your answer is more portable :) although note `os.system` is deprecated – Chris_Rands Aug 29 '16 at 13:03
  • @Chris_Rands Deprecated? I didn't know that... I don't see it marked in the [docs](https://docs.python.org/3/library/os.html#os.system) though, where have you read that? – BPL Aug 29 '16 at 13:10
  • @BPL It says in the docs you link to that using `subprocess` module is prefered to `os.system`, also see: https://docs.python.org/3/library/subprocess.html – Chris_Rands Aug 29 '16 at 15:10
3

If I've understood correctly you're looking for this type of solution:

import random
import time
import os


def clear_screen():
    os.system('cls' if os.name == 'nt' else 'clear')

a = 0
while True:
    clear_screen()

    statement = """
    Line {}
    Line {}
    Line {}
    Value = {}
    """.format(random.random(), random.random(), random.random(), a)
    print(statement, end='\r')
    time.sleep(1)
    a += 1

This solution won't work with some software like IDLE, Sublime Text, Eclipse... The problem with running it within this type of software is that clear/cls uses ANSI escape sequences to clear the screen. These commands write a string such as "\033[[80;j" to the output buffer. The native command prompt is able to interpret this as a command to clear the screen but these pseudo-terminals don't know how to interpret it, so they just end up printing small square as if printing an unknown character.

If you're using this type of software, one hack around could be doing print('\n' * 100), it won't be the optimal solution but it's better than nothing.

BPL
  • 9,632
  • 9
  • 59
  • 117
  • This works only if he is working in the terminal. What if he is using the IDLE or some other interpreter? – TheLazyScripter Aug 29 '16 at 12:51
  • nice copy paste ! – dsgdfg Aug 29 '16 at 12:53
  • 1
    @TheLazyScripter I've never used that IDLE thing after working with python for many years so personally I don't care about it. Also, the OP didn't mention that requirement so the assumption is he's using some real tool – BPL Aug 29 '16 at 12:56
  • @BPL I use Eclipse and your method doesn't work. I was not specifying that it wouldn't work in IDLE, I was saying that it ONLY works on CMD or some other terminal... – TheLazyScripter Aug 30 '16 at 04:10
2

You could use curses for this.

#!/usr/bin/python3

import curses
from time import sleep
from random import random

statement = """
Line {}
Line {}
Line {}
Value = {}"""

screen = curses.initscr()
n = 0

while n < 20:
    screen.clear()
    screen.addstr(0, 0, statement.format(random(), random(), random(), n))
    screen.refresh()
    n += 1
    sleep(0.5)

curses.endwin()
Germar
  • 436
  • 4
  • 24