teste=input('Olá qual o seu nome?')
How do I do if the user takes more than a certain time interval to take some action. Eg: write on the screen 'You took too long'.
teste=input('Olá qual o seu nome?')
How do I do if the user takes more than a certain time interval to take some action. Eg: write on the screen 'You took too long'.
The
signal.alarm
function is only available for Unix environment.
You can use the signal
module. First, we define a function that will handle the case that the user is inactive and their time expires. For simplicity, I'll just throw an exception:
def timeout():
raise Exception('Seu tempo acabou!')
Finally, the magic. With the signal
module, we define a time signal in which the timeout
function is responsible for processing. We do this simply with:
signal.signal(signal.SIGALRM, timeout)
And then we do:
try:
signal.alarm(5)
name = input('Qual é o seu nome? ')
signal.alarm(0)
print('Seja bem-vindo,', name)
except Exception as e:
print(e)
That is, we set the alarm time of our signal to 5 seconds, that is, from this moment run for 5 seconds, the timeout
function will be executed; we try to read the user name and, if successful, cancel our signal by setting the alarm time to 0. If the user is inactive, the signal will not be canceled and after 5 seconds, the timeout
function will be executed, triggering the exception and therefore being caught by try
, waxing the program.
The complete code would look like:
import signal
def timeout(signum, frame):
raise Exception('Seu tempo acabou!')
signal.signal(signal.SIGALRM, timeout)
signal.alarm(5)
try:
signal.alarm(5)
name = input('Qual é o seu nome? ')
signal.alarm(0)
print('Seja bem-vindo,', name)
except Exception as e:
print(e)
See working at Repl.it | GitHub GIST
Obviously you can make everything much more beautiful by implementing a decorator in Python. For example:
import signal
def timeout(seconds):
def decorator(function):
def wrapper(*args, **kwargs):
def handler(signum, frame):
raise Exception(f'Timeout of {function.__name__} function')
signal.signal(signal.SIGALRM, handler)
signal.alarm(seconds)
result = function(*args, **kwargs)
signal.alarm(0)
return result
return wrapper
return decorator
So, to define the timeout of any function, just do:
@timeout(seconds=5)
def read_user_name():
name = input('Qual é o seu nome? ')
print('Seja bem-vindo,', name)
And use it with:
try:
read_user_name()
except Exception as e:
print(e)
You can even use it in other situations, such as downloading a file with the requests
module:
@timeout(seconds=30)
def download_awesome_image(save):
with open(save, 'wb') as stream:
response = requests.get('http://url.to/awesome_image.jpg')
stream.write(response.content)
try:
download_awesome_image(save='awesome_image.jpg')
except Exception as e:
print('Desculpe-me, mas demorou muito e eu não quis esperar')
An alternative that works also in Windows is to use the multiprocessing
module, defining a distinct process to execute the task. Similar to the previous one, we can define a decorator:
from multiprocessing import TimeoutError
from multiprocessing.pool import ThreadPool
def timeout(seconds):
def decorator(function):
def wrapper(*args, **kwargs):
pool = ThreadPool(processes=1)
result = pool.apply_async(function, args=args, kwds=kwargs)
try:
return result.get(timeout=seconds)
except TimeoutError as e:
return e
return wrapper
return decorator
@timeout(5)
def read_user_name():
return input('Nome? ')
name = read_user_name()
if isinstance(name, TimeoutError):
print('Demorou demais, parsa!')
else:
print('Olá', name)
See working at Repl.it | GitHub GIST
Note that since the function will be executed in another process, the exception that is thrown at the time expires does not influence the original process, so to get around this, I returned the instance of the exception itself and checked the type before treat the value of the variable.
I had this doubt a while back. The way I found it was this.
import time
print('Pausa de 5 segundos (Aperte Ctrl-C para inserir algo)')
try:
for i in range(0,5):
time.sleep(1)
except KeyboardInterrupt:
input("Entrada: ")