Slow, word-by-word terminal printing in Python? [duplicate] - python

This question already has answers here:
How to print one character at a time on one line?
(4 answers)
Closed 9 years ago.
I'm writing a Python app involving a database. For the hell of it, I'm including an easter egg. If the user decides to nuke his database, all this from a terminal, he'll be prompted to confirm with a simple (y/n). But if he types DLG2209TVX instead, the lines from that scene of WarGames will print. Doubt anybody will ever find it unless they look through my source, but that's okay.
The problem is that simply printing the lines plays the scene way too fast and really just ruins it. I implemented a timer between each character's lines to slow things down, and it's better, but it still seems unnatural. Is there a standardized way to slowly print each word or character out instead of doing it lines at a time? Or should I just start adding timers between words?

Standardized? Not that I know of. But try this:
import random
import sys
import time
def slowprint(s):
for c in s + '\n':
sys.stdout.write(c)
sys.stdout.flush() # defeat buffering
time.sleep(random.random() * 0.1)
slowprint('Hello, world.')
Adjust the 0.1 to change the maximum delay between characters, and add lengthy time.sleep()s between lines to add more dramatic effect.

import sys
import time
for c in gettysburg_address:
sys.stdout.write(c)
sys.stdout.flush()
# 110 baud:
time.sleep( 8./110 )
# 300 baud:
# time.sleep( 8./300 )

You can also try curses.delay_output():
In [48]: import curses
In [49]: for x in "foo bar":
sys.stdout.write(x) #prints each char with a delay of 100ms
curses.delay_output(100)
....:
foo bar

Related

Is there a way to prevent automatic newline on python command line? [duplicate]

This question already has answers here:
How to print without a newline or space
(26 answers)
Closed 3 years ago.
I am making a command line game engine in python. However, when I attempt to print a command, it newlines and creates a jittery frame.
Adding the end attribute bogs down my computer and nearly crashes the shell. The dupe uses sys.stdout.write('') newline sys.stdout.flush or print'', or print('',end=''). all bog down shell and crash it. print('') doesn't bog down though which is weird.
#this is enough code to demonstrate the problem
while true:
print(' = === ===== ======= ========= =========== ============= YYYYYYYYYYY ================================================================================')
#crash issue
import sys
while True:
sys.stdout.write('mooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo')
sys.stdout.flush()
I expect the screen to fill, instead it wobbles up and down.
I am not sure if I understood your question correctly, but I’m thinking you do not want to print a new line with each call to the print() function.
If so, the print function has an optional argument end, that is set by default as \n (this, creating a new line if not specified otherwise). If you don’t want this to happen, you can simply use the print function as:
print(your_argument, end=“”)
Replacing your_argument with whatever you want to print out.

How to clear a screen in Python? [duplicate]

This question already has answers here:
How to clear the interpreter console?
(31 answers)
Clear terminal in Python [duplicate]
(27 answers)
Closed 3 years ago.
I am running on Python 3.7.1 and I've been trying to find a way to clear a screen of any previously printed messages. The problem is that os.system("cls") does nothing, it only makes a small window pop up for a fraction of a second, then it closes. I've tried to add a \n at the end and multiplying it by how many letters there are, still not working.
Unfortunately, there’s no built-in keyword or function/method to clear the screen. So, we do it on our own.
We can use ANSI escape sequence but these are not portable and might not produce desired output.
# import only system from os
from os import system, name
# import sleep to show output for some time period
from time import sleep
# define our clear function
def clear():
# for windows
if name == 'nt':
_ = system('cls')
# for mac and linux(here, os.name is 'posix')
else:
_ = system('clear')
# print out some text
print('hello geeks\n'*10)
# sleep for 2 seconds after printing output
sleep(2)
# now call function we defined above
clear()
I don't think that there is a way, or at least have never seen one. However, there is a workaround which would look like
print "\n" * 100.
This will simply print 100 newlines, which will clear the screen for you.
You could also put it in a function
def cls(): print "\n" * 100
And then when you need it just call it with cls()

progress of loop indicator [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Python Progress Bar
I am running a for loop 10,000 times,
but inside the loop there are a lot of calculations going on.
I would like to print out a progress message to the console informing me how far along in the loop the program is how much longer I might have to wait.
the basic loop is
n = 10000
for i in range(n):
do_stuff_method()
if(i%100 == 0):
print (float(i)/n)*100,
This prints out a percentage message on the same line, but the problem is that the next thing that I print out is also printed out on the same screen. That, and since there are 99 prinouts, the console gets pretty wide and there is a lot of scrolling across.
What I would really like is for the console to print out the current % done, and an estimated time to finsih on the one line replace that which had been previously printed, so there doesn't have to be a lot scrolling.
Can this be done?
Cheers,
Davy
In your case you can do it simply by changing your print line to be:
print "\r{0}".format((float(i)/n)*100),
Or you can try it like this instead of print:
sys.stdout.write("\r{0}".format((float(i)/n)*100))
sys.stdout.flush()

Usage of sys.stdout.flush() method

What does sys.stdout.flush() do?
Python's standard out is buffered (meaning that it collects some of the data "written" to standard out before it writes it to the terminal). Calling sys.stdout.flush() forces it to "flush" the buffer, meaning that it will write everything in the buffer to the terminal, even if normally it would wait before doing so.
Here's some good information about (un)buffered I/O and why it's useful:
http://en.wikipedia.org/wiki/Data_buffer
Buffered vs unbuffered IO
Consider the following simple Python script:
import time
import sys
for i in range(5):
print(i),
#sys.stdout.flush()
time.sleep(1)
This is designed to print one number every second for five seconds, but if you run it as it is now (depending on your default system buffering) you may not see any output until the script completes, and then all at once you will see 0 1 2 3 4 printed to the screen.
This is because the output is being buffered, and unless you flush sys.stdout after each print you won't see the output immediately. Remove the comment from the sys.stdout.flush() line to see the difference.
As per my understanding, When ever we execute print statements output will be written to buffer. And we will see the output on screen when buffer get flushed(cleared). By default buffer will be flushed when program exits. BUT WE CAN ALSO FLUSH THE BUFFER MANUALLY by using "sys.stdout.flush()" statement in the program. In the below code buffer will be flushed when value of i reaches 5.
You can understand by executing the below code.
chiru#online:~$ cat flush.py
import time
import sys
for i in range(10):
print i
if i == 5:
print "Flushing buffer"
sys.stdout.flush()
time.sleep(1)
for i in range(10):
print i,
if i == 5:
print "Flushing buffer"
sys.stdout.flush()
chiru#online:~$ python flush.py
0 1 2 3 4 5 Flushing buffer
6 7 8 9 0 1 2 3 4 5 Flushing buffer
6 7 8 9
import sys
for x in range(10000):
print "HAPPY >> %s <<\r" % str(x),
sys.stdout.flush()
As per my understanding sys.stdout.flush() pushes out all the data that has been buffered to that point to a file object.
While using stdout, data is stored in buffer memory (for some time or until the memory gets filled) before it gets written to terminal. Using flush() forces to empty the buffer and write to terminal even before buffer has empty space.
You can see the differences b/w these two
import sys
for i in range(1,10 ):
sys.stdout.write(str(i))
sys.stdout.flush()
for i in range(1,10 ):
print i
In the first case, the characters are output one by one after each is written, because of the flush. In the second case, the characters are buffered by Python until it thinks it's got something worth the effort to write, and then written all in a batch.
If you add, say, a time.sleep(0.2) in the loops, this becomes more obvious.
Imagine you have a toy box where you keep all your toys. When you want to play with a toy, you usually take it out of the box, right?
In a similar way, when you write something on the computer, it gets stored in a temporary place called a buffer. Think of it like a toy box for computer data. The computer waits until the toy box is full before it takes the data out of the box and shows it to you on the screen.
However, sometimes you might want to play with a toy right away, without waiting for the toy box to fill up with other toys. This is like when you call sys.stdout.flush() in Python. It tells the computer to take the data out of the buffer and show it to you on the screen right away, without waiting for the buffer to fill up.

Dynamic terminal printing with python

Certain applications like hellanzb have a way of printing to the terminal with the appearance of dynamically refreshing data, kind of like top().
Whats the best method in python for doing this? I have read up on logging and curses, but don't know what to use. I am creating a reimplementation of top. If you have any other suggestions I am open to them as well.
The simplest way, if you only ever need to update a single line (for instance, creating a progress bar), is to use '\r' (carriage return) and sys.stdout:
import sys
import time
for i in range(10):
sys.stdout.write("\r{0}>".format("="*i))
sys.stdout.flush()
time.sleep(0.5)
If you need a proper console UI that support moving the pointer etc., use the curses module from the standard library:
import time
import curses
def pbar(window):
for i in range(10):
window.addstr(10, 10, "[" + ("=" * i) + ">" + (" " * (10 - i )) + "]")
window.refresh()
time.sleep(0.5)
curses.wrapper(pbar)
It's highly advisable to use the curses.wrapper function to call your main function, it will take care of cleaning up the terminal in case of an error, so it won't be in an unusable state afterwards.
If you create a more complex UI, you can create multiple windows for different parts of the screen, text input boxes and mouse support.
As most of the answers have already stated, you really have little option on Linux but to use ncurses. But what if you aren't on Linux, or want something a little more high-level for creating your terminal UI?
I personally found the lack of a modern, cross-platform terminal API in Python frustrating, so wrote asciimatics to solve this. Not only does it give you a simple cross-platform API, it also provides a lot of higher level abstractions for UI widgets and animations which could be easily used to create a top-like UI.
Sending output to the terminal via the print() command can be done without scrolling if you use the attribute "end".
The default is end='\n' which is a new line.
To suppress scrolling and overwrite the whole previous line, you can use the RETURN escape which is '\r'.
If you only want to rewrite the last four characters, you can use a few back-spaces.
print(value, "_of_", total, end='\r')
NOTE
This works for the standard system terminal. The terminal emulator in some tools like IDLE has an error and the '\r' does not work properly, the output is simply concatenated with some non-printable character between.
BONUS INFORMATION FOR print()
In the example above, the spaces on each side of "of" are meant to insure white-space between my values and the word "of". However, the default separater of the print() is a " " (space) so we end up with white space between the value and underscore of "_of_".
>> print (value, "_of_", total, end='\r')
8 _of_ 17
The sepparator attribute, sep, can be used to set character between printed items. In my example, I will change it to a null string ('') to make my output suit my needs.
>> print (value, "_of_", total, sep='', end='\r')
8_of_17
I hacked this script using curses. Its really a ad-hoc solution I did for a fun. It does not support scrolling but I think its a good starting point if you are looking to build a live updating monitor with multiple rows on the terminal.
https://gist.github.com/tpandit/b2bc4f434ee7f5fd890e095e79283aec
Here is the main:
if __name__ == "__main__":
stdscr = curses.initscr()
curses.noecho()
curses.cbreak()
curses.start_color()
curses.init_pair(1, curses.COLOR_GREEN, curses.COLOR_BLACK)
curses.init_pair(2, curses.COLOR_RED, curses.COLOR_BLACK)
curses.init_pair(3, curses.COLOR_YELLOW, curses.COLOR_BLACK)
curses.init_pair(4, curses.COLOR_CYAN, curses.COLOR_BLACK)
try:
while True:
resp = get_data()
report_progress(get_data())
time.sleep(60/REQUESTS_PER_MINUTE)
finally:
curses.echo()
curses.nocbreak()
curses.endwin()
When I do this in shell scripts on Unix, I tend to just use the clear program. You can use the Python subprocess module to execute it. It will at least get you what you're looking for quickly.
import time
for i in range(10):
print('\r{}>'.format('='*i), end='')
time.sleep(0.5)
I don't think that including another libraries in this situation is really good practice. So, solution:
print("\rCurrent: %s\t%s" % (str(<value>), <another_value>), end="")

Categories

Resources