Dynamic single-line printing in Python (time?) - python

I'd like to make a simple clock (CLI) that prints the time into one line, and updates it every second. Is this even possible? Should I just print a new line every second?
This is what I have at the moment, which functions terribly:
import calendar, time
a = 1
while a == 1:
print (calendar.timegm(time.gmtime()))

If I understand, what you want to do is write the time, then, a second later, overwrite it with the new time, and so on.
On most terminals, printing a carriage return without a newline will take you back to the start of the same line. So, you can almost just do this:
print('\r{}'.format(calendar.timegm(time.gmtime())), end='')
In general, there's a problem with this: the carriage return doesn't erase the existing text, it just lets you overwrite it. So, what happens if the new value is shorter than the old one? Well, in your case, that isn't possible; you're printing a 10-digit number that can never turn into a 9-digit number. But if it were a problem, the easiest solution would be to change that {} to something like {<70}, which will pad a short line with spaces, up to 70 characters. (Of course if your lines could be longer than 70 character, or your terminal could be narrower than 70, don't use that number.)
Meanwhile, if you just do this over and over as fast as possible, you're wasting a lot of CPU and I/O, and possibly screwing up your terminal's scrollback buffer, and who knows what else. If you want to do this once per second, you should sleep for a second in between.
So:
while True:
print('\r{}'.format(calendar.timegm(time.gmtime())))
time.sleep(1)
If you want to get fancy, you can take over the whole terminal with curses on most non-Windows platforms, msvcrt console I/O on Windows, or even manually printing out terminal escape sequences. But you probably don't want to get fancy.

print function print newline (\n) after the string you passed. Specify carriage return (\r) explicitly does what you want.
To print every second, call time.sleep(1) after printing.
import calendar
import time
while 1:
print(calendar.timegm(time.gmtime()), end='\r')
time.sleep(1)
UPDATE
To make cursor remains at the end of the line, prepend \r:
print('\r', calendar.timegm(time.gmtime()), sep='', end='')

Related

Why does IDLE add a newline after my code?

On my saving a .py file, IDLE (Python 3.9 x64) will add a newline after the code itself. It is setting off my OCD while making me curious. For instance, take this entirely original last line of a program while coding:
print("Hello, world!")
Yet, when saved, it becomes:
print("Hello, world!")
# ghost line!
What is the significance of that extra line—can I turn it off?
IDLE has made sure that a file being saved ends with a newline ('\n') since the first commit in 2000. I believe that at one time the Python compiler required that every line, including the last, be complete, ending with a newline. It may be more lax now, under some circumstances, but I am not sure. There may be other things one does with a file that could require the proper ending.
Ghosts do not exist, and neither does the ghost line. A line of 0 characters is not really a line. The cursor at the left margin after the last line is ready to start a new line.
It is the best practice of Python to have an extra line at the end of the code. If you explicitly go and delete the last line, then it won't be there. But, my suggestion would be to keep it. It's always better to follow best practices.

How to overwrite a line with carriage return, using a for-loop in Python?

I'm trying to print out a string with the end=\r to send the cursor back to beginning of the line, and overwrite the printed string using a for loop
This is the code thus far I got :
import time
print("░░░░░░░░░░░░░", end='\r')
for i in ("SECRET"):
print(i ,end='')
time.sleep(0.3)
Ideally, it should slowly overwrite some of the dotted pattern characters with characters from `"SECRET" every 0.3 seconds.
However, when run, the for loop instead iterates and prints characters on a single space, overwriting the characters it prints out itself, instead of advancing to the next available space, overwriting the dot pattern there and typing out the remaining characters in the string it iterates over
Removing the entire print statement associated with the dotted pattern characters allows the loop to function normally, printing out the string it iterates over properly, however, it is needed for the loop to print out the string and overwrite the dotted characters
Essentially, I want to overwrite some of the dotted pattern characters one by one using characters from the string the for loop iterates over, with the help of \r
I am on Ubuntu Studio
Screen output is line-buffered. This means that when you print something followed by a newline it appears on the screen immediately, but if you print something without a newline it might take a while to appear.
This is what's happening to you -- the output inside the for loop is not followed by a newline, so it doesn't appear onscreen immediately.
You can add flush=True to the print call to force the output to appear immediately instead of waiting:
print(i, end='', flush=True)
you can't overwrite characters in python.
you can, though, clear the whole screen by using os.system('cls') on windows or os.system('clear') on linux and unix.
here is the full code:
import time, os
output = '░░░░░░░░░░░░░'
for i in range(7):
print(output)
output = "SECRET"[:i]+output[i:]
time.sleep(0.3)
if os.name == 'nt': #on windows
os.system("cls")
else:
os.system("clear") #not on windows
print(output)
also, this will only work when you are not running from the shell and if you want to see the full output, write time.sleep(1) at the end.

\r in Python does not delete the entire line

i have a quite complex problem, but here is the "simplest version" so you can better understand it.
import time
for i in range(10):
time.sleep(1)
print('{}\r'.format(i), end="")
and here everything works fine, the problem comes when i try to make a countdown
import time
for i in range(10):
time.sleep(1)
print('{}\r'.format(10-i), end="")
the output is 10... then 90... 80... 70 and so on, it seems like if the second cipher of the 10 is not cancelled. can someone tell me why?
\r moves the cursor to the beginning of the line, but it doesn't "clear" anything already printed unless you overwrite it (this may be platform-dependent). Thus, the 0 character will remain visible. You can deal with that by always printing a "fixed-width" column, so that empty spaces are printed to blank out anything left over from before. You can also just put the CR in the end param.
Thus:
import time
for i in range(10):
time.sleep(1)
print('{: <3}'.format(10-i), end='\r')
This uses a format specifier to indicate a space-filled, <left-aligned, 3-width column. You can change the 3 to any higher number depending on how many digits your counter needs.
It's caused by a simple error, you are missing a space before the \r:
Your Code:
print('{}\r'.format(10-i), end="")
# > 10,90,80
Change it to:
print('{} \r'.format(10-i),
#> 10, 9, 8
The issue is like old typewriters when you press \r carriage return it goes to line start and chages one character from there. so 10 will become 90 as the first character changes.
import time
for i in range(10):
time.sleep(1)
print('{:02d}'.format(10-i), end="\r")
So one potential solution is to fix the width. here I have made it 2 digit

Python treating carriage return as newline character. What can I do instead?

I want to write a code which prints Loading, and then erases that and prints Loading., erases that too and prints Loading.. and so on. So I tried using \r, but python interprets it as \n. Is there a charcter I can use instead of \r?
I've tried using \b instead, but Python doesn't recognize it, either. For example, if I print qwerty\buiop, it just prints qwertyuiop.
This is the code I tried, using carriage return:
import time
for y in range (5):
for i in range (4):
print("Loading","."*i, end="\r")
time.sleep(0.5)
However, instead of printing how I want it to, it prints like
Loading
Loading .
Loading ..
Loading ...
in different lines.
How do I solve this problem? Is there a different character I can use?
I'm using IDLE and MacOS.
Thank you so much!
I know you probably know an answer by now, but for people still looking for one:
Try using an empty end, while using \r at the beginning of each print to overwrite the previous one.
import time
for i in range (4):
print("\rLoading","."*i, end ="")
time.sleep(0.5)
Try running your program in terminal.
Different shells interpret the \r character in different ways. A lot of them will write out each print as a separate output rather than one ongoing stream. Terminal should interpret it the way you are thinking

Python - print long string in terminal but stay at the beginning of the string

I am writing a script that runs in the terminal and that displays a (long) multiple line string. My problem is that, when the string is printed, the terminal automatically places the cursor at the end of the string.
The string being longer than the number of lines in the terminal, I only see the last 72 lines of my string (my terminal window has 72 lines), so it forces to scroll up to the beginning of the string every time I run that script, and it turns out to be pretty annoying.
Is there a way to go back to the beginning of the string once it's printed?
End of string, the cursor is at the bottom:
Beginning of the string, ~200 lines above, where I want to be after the script runs:
I thought of using curses, but that seems to be overkill for what I am looking for.
Also, I'm on Mac OS and I don't particularly care about portability
While curses is the portable solution, try printing the sequence ESC [ H. It will likely work on all of the terminals you care about.
print "\033[H"
Reference:
https://en.wikipedia.org/wiki/ANSI_escape_code
Re your comment you made on Aug 28, 2015 at 1:51:
I think what you are looking for is printing this escape code:
print("\033[F")

Categories

Resources