I am making a game/quiz in Python, but ran into a small issue. I made a function to print one letter at a time, but when I use that function for an input, it does not work and prints all at once. I've tried making a string for the input and multiple other things. To fix this temporarily, I have just been printing my question, and then using an input function to make an input, but I'm wondering if there is a better way. Here is my code:
import time
import sys
def input1():
input("")
def oneprint(s):
for c in s:
sys.stdout.write(c)
sys.stdout.flush()
time.sleep(0.05)
oneprint("Welcome. This is a very easy test. Do as you are told.")
time.sleep(3)
q1 = "\nLet's get started. What is my favorite color?"
oneprint(q1)
input1()
I think you may want to add the same for loop that requires c inside of your script in your input1 function, here is an example of how you could do such a thing:
import time
import sys
def oneprint(s):
for c in s:
sys.stdout.write(c)
sys.stdout.flush()
time.sleep(0.05)
def input1():
inp = input("")
oneprint(inp)
oneprint("Welcome. This is a very easy test. Do as you are told.")
time.sleep(3)
q1 = "\nLet's get started. What is my favorite color?"
oneprint(q1)
input1()
if you try this it will print the desired color that was answered by the player by getting the input and getting each letter and writing it and flushing it through the oneprint function.
This will display the input and oneprint it:
import time
import sys
def oneprint(s):
for c in s:
sys.stdout.write(c)
sys.stdout.flush()
time.sleep(0.05)
oneprint("Welcome. This is a very easy test. Do as you are told.")
time.sleep(3)
oneprint("\nLet's get started. What is my favorite color?")
oneprint(input("\n"))
This will hide the input, and oneprint it:
import time
import sys
from getpass import getpass
def oneprint(s):
for c in s:
sys.stdout.write(c)
sys.stdout.flush()
time.sleep(0.05)
oneprint("Welcome. This is a very easy test. Do as you are told.")
time.sleep(3)
oneprint("\nLet's get started. What is my favorite color?")
oneprint(getpass("\n>"))
Where getpass is a password formatted input
I figured out the answer. If anyone else is having this issue you should just do:
input(oneprint(Blah Blah Blah Your Question Here))
Related
I've been trying to find a good limited-input-time code for Python scripts and I finally got a code to work:
from threading import Timer
timeout = 5
t = Timer(timeout, print, ["Time's up!"])
t.start()
entry = input('> ')
t.cancel()
but, I need to be able to run a function when the timer ends.
Also - I want the function called inside of the timer code - otherwise if you type your entry before the timer runs out, the function will still be called no matter what.
Could anyone kindly edit this code I have to be able to run a function when the timer ends?
If it is fine that you block the main thread when the user has not provided any answer, the above code that you have shared might work.
Otherwise you could use msvcrt in the following sense:
import msvcrt
import time
class TimeoutExpired(Exception):
pass
def input_with_timeout(prompt, timeout, timer=time.monotonic):
sys.stdout.write(prompt)
sys.stdout.flush()
endtime = timer() + timeout
result = []
while timer() < endtime:
if msvcrt.kbhit():
result.append(msvcrt.getwche()) #XXX can it block on multibyte characters?
if result[-1] == '\n': #XXX check what Windows returns here
return ''.join(result[:-1])
time.sleep(0.04) # just to yield to other processes/threads
raise TimeoutExpired
The above code is compliant with Python3 and you will need to test it.
Reading from the Python Documentation https://docs.python.org/3/library/threading.html#timer-objects
I have come up with the following snippet which might work(Try running in your command line prompt)
from threading import Timer
def input_with_timeout(x):
def time_up():
answer= None
print('time up...')
t = Timer(x,time_up) # x is amount of time in seconds
t.start()
try:
answer = input("enter answer : ")
except Exception:
print('pass\n')
answer = None
if answer != True: # it means if variable has something
t.cancel() # time_up will not execute(so, no skip)
input_with_timeout(5) # try this for five seconds
How can I print directly after my input without waiting until the user answered the input statement?
def InputSaveName():
try:
import os, sys, time, pickle, colorama
except Exception as e:
print("Some modules are mssing! Install them and try again! {}".format(e))
colorama.init()
print("+----------------------+")
print("What is your name adventurer?")
name = input("> ")
print("+----------------------+")
I want the bottom line to print without waiting for the user to put something in the input statement. In short: I want the code to run simultaneously.
This seems to be an XY problem. You do not really want to use threading to run multiple lines of code at once. To build a complex full-screen terminal application, you should have a look at curses:
import curses
def getname(stdscr):
stdscr.clear()
stdscr.addstr(0, 0, "+---------------------------+")
stdscr.addstr(1, 0, "What is your name adventurer?")
stdscr.addstr(2, 0, "> ")
stdscr.addstr(3, 0, "+---------------------------+")
curses.echo()
return stdscr.getstr(2, 3, 20)
s = curses.wrapper(getname)
print("Name is", s)
This only asks for the name and then returns, but you can also add lines, or replace existing lines on the existing screen and refresh the screen.
Without being 100% sure if it works in the specific examples you have typed in your question because of access to the standard output.
If you want to run things in parallel you can read about threads / subprocess https://docs.python.org/3/library/subprocess.html
or fork / multiprocessing
https://docs.python.org/3/library/multiprocessing.html
EDIT after op's EDIT ;-)
What you want to do seems very similar to what's described in this question Python nonblocking console input
This might be what you are looking for.
There is a "background process" running while waiting for your input using two separate threads.
import time
import threading
def myInput():
print("Type your name when ready!")
name = input()
print("Your name is: ", name)
def backgroundProcess():
while (True):
print("Some code is running...")
time.sleep(1)
inputThread = threading.Thread(target=myInput)
processThread = threading.Thread(target=backgroundProcess)
inputThread.start()
processThread.start()
You can use threading or multiprocessing modules:
import threading
def makeAsomethingOne():
print('I am One!')
def makeAsomethingTwo(printedData=None):
print('I am Two!',printedData)
name = input("> ")
firstThread = threading.Thread(target=makeAsomethingOne)
twiceThread = threading.Thread(target=makeAsomethingTwo,args=[name])
firstThread.start()
twiceThread.start()
This code runs almost simultaneously.
I'm trying to create application which needs to get user input data while it prints things in a console at the same time.
import threading
import time
def F1():
for i in range (100):
print (i)
time.sleep(1)
def input_data():
txt = input('>')
print(txt)
w1 = threading.Thread(target=F1)
w2 = threading.Thread(target=input_data)
w1.start()
w2.start()
But this way function input() stops all threads.
Is it possible to do it asynchronously in a python interpreter?
(I know that i could do it in tkinter easily.)
Note: I want to do this without using any external packages, like PyGame, etc.
I am attempting to capture individual keypresses as they arrive and perform an action for specific characters, whether I simply want to "re-echo" the character, or not display it at all and do something else.
I have found a cross-platform (though not sure about OS X) getch() implementation because I do not want to read a whole line like input() does:
# http://code.activestate.com/recipes/134892/
def getch():
try:
import termios
except ImportError:
# Non-POSIX. Return msvcrt's (Windows') getch.
import msvcrt
return msvcrt.getch
# POSIX system. Create and return a getch that manipulates the tty.
fd = sys.stdin.fileno()
old_settings = termios.tcgetattr(fd)
try:
tty.setraw(fd)
ch = sys.stdin.read(1)
finally:
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
return ch
[Attempt 1]
I first tried a simple while-true loop to poll getch, but if I type too fast, characters go missing. Reducing the sleep time makes it worse. The debug statements only print on press of the enter key and not consistently in time nor position. (It appears there might be some line buffering going on?) Taking out the loop and sleep lets it work once but perfectly.
#!/usr/bin/env python3
import sys
import tty
import time
def main():
while True:
time.sleep(1)
sys.stdout.write(" DEBUG:Before ")
sys.stdout.write(getch())
sys.stdout.write(" DEBUG:After ")
if __name__ == "__main__":
main()
[Attempt 2]
I got an example for using a threaded approach (https://stackoverflow.com/a/14043979/2752206) but it "locks up" and won't accept any input (including Ctrl-C, and etc)..
#!/usr/bin/env python3
import sys
import tty
import time
import threading
key = 'Z'
def main():
threading.Thread(target=getchThread).start()
while True:
time.sleep(1)
sys.stdout.write(" DEBUG:Before ")
sys.stdout.write(key)
sys.stdout.write(" DEBUG:After ")
def getchThread():
global key
lock = threading.Lock()
while True:
with lock:
key = getch()
if __name__ == "__main__":
main()
Does anyone have any advice or guidance? Or more importantly, can someone explain why the two attempts do not work? Thanks.
First off, I don't really thing you need multithreading. You'd need that if you, for example, wanted to do some tasks like drawing on screen or whatever and capturing keys while you do this.
Let's consider a case where you only want to capture keys and after each keypress execute some action: Exit, if x was pressed, otherwise just print the character. All you need for this case is simple while loop
def process(key):
if key == 'x':
exit('exitting')
else:
print(key, end="", flush=True)
if __name__ == "__main__":
while True:
key = getch()
process(key)
Notice absence of sleep(). I am assuming you thought getch() won't wait for user input so you set 1s sleep time. However, your getch() waits for one entry and then returns it. In this case, global variable is not really useful, so you might as well just call process(getch()) inside the loop.
print(key, end="", flush=True) => the extra arguments will ensure pressed keys stay on one line, not appending newline character every time you print something.
The other case, where you'd want to execute different stuff simultaneously, should use threading.
Consider this code:
n = 0
quit = False
def process(key):
if key == 'x':
global quit
quit = True
exit('exitting')
elif key == 'n':
global n
print(n)
else:
print(key, end="", flush=True)
def key_capturing():
while True:
process(getch())
if __name__ == "__main__":
threading.Thread(target=key_capturing).start()
while not quit:
n += 1
time.sleep(0.1)
This will create global variable n and increment it 10 times a second in main thread. Simultaneously, key_capturing method listens to keys pressed and does the same thing as in previous example + when you press n on your keyboard, current value of the global variable n will be printed.
Closing note: as #zondo noted, you really missed braces in the getch() definition. return msvcrt.getch should most likely be return msvcrt.getch()
I have an infinite while loop that I want to break out of when the user presses a key. Usually I use raw_input to get the user's response; however, I need raw_input to not wait for the response. I want something like this:
print 'Press enter to continue.'
while True:
# Do stuff
#
# User pressed enter, break out of loop
This should be a simple, but I can't seem to figure it out. I'm leaning towards a solution using threading, but I would rather not have to do that. How can I accomplish this?
You can use non-blocking read from stdin:
import sys
import os
import fcntl
import time
fl = fcntl.fcntl(sys.stdin.fileno(), fcntl.F_GETFL)
fcntl.fcntl(sys.stdin.fileno(), fcntl.F_SETFL, fl | os.O_NONBLOCK)
while True:
print("Waiting for user input")
try:
stdin = sys.stdin.read()
if "\n" in stdin or "\r" in stdin:
break
except IOError:
pass
time.sleep(1)
I think you can do better with msvcrt:
import msvcrt, time
i = 0
while True:
i = i + 1
if msvcrt.kbhit():
if msvcrt.getwche() == '\r':
break
time.sleep(0.1)
print(i)
Sadly, still windows-specific.
On python 3.5 you can use the following code. It can be adjusted for a specific keystroke. The while loop will keep running until the user presses a key.
import time
import threading
# set global variable flag
flag = 1
def normal():
global flag
while flag==1:
print('normal stuff')
time.sleep(2)
if flag==False:
print('The while loop is now closing')
def get_input():
global flag
keystrk=input('Press a key \n')
# thread doesn't continue until key is pressed
print('You pressed: ', keystrk)
flag=False
print('flag is now:', flag)
n=threading.Thread(target=normal)
i=threading.Thread(target=get_input)
n.start()
i.start()
I could not get some of the popular answers working. So I came up with another approach using the CTRL + C to plug in user input and imbibe a keyboard interrupt. A simple solution can be using a try-catch block,
i = 0
try:
while True:
i+=1
print(i)
sleep(1)
except:
pass
# do what you want to do after it...
I got this idea from running a number of servers like flask and django. This might be slightly different from what the OP asked, but it might help someone else who wanted a similar thing.
Using the msvcrt module as thebjorn recommended I was able to come up with something that works. The following is a basic example that will exit the loop if any key is pressed, not just enter.
import msvcrt, time
i = 0
while True:
i = i + 1
if msvcrt.kbhit():
break
time.sleep(0.1)
print i
What you need is a non-blocking raw input, if you don't want to use threads there is a simple solution like this one below where he is doing a timeout of 20 ms and then raise and exception if the user doesn't press a key, if he does then the class returns the key pressed.
import signal
class AlarmException(Exception):
pass
def alarmHandler(signum, frame):
raise AlarmException
def nonBlockingRawInput(prompt='', timeout=20):
signal.signal(signal.SIGALRM, alarmHandler)
signal.alarm(timeout)
try:
text = raw_input(prompt)
signal.alarm(0)
return text
except AlarmException:
print '\nPrompt timeout. Continuing...'
signal.signal(signal.SIGALRM, signal.SIG_IGN)
return ''
Source code
I have defined the function which ask number input from the user and returns the factorial of that number. If user wants to stop they have to press 0 and then it will exit from the loop. We can specify any specific key to input 'n' to exit from the loop.
import math
def factorial_func(n):
return math.factorial(n)
while True:
n = int(input("Please enter the number to find factorial: "))
print(factorial_func(n))
if n == 0:
exit()