3
teste = input('Olá qual o seu nome?')
How to run something if the user takes longer than a certain amount of time to respond to input?
Example:
- Write on screen
Você demorou demais
.
3
teste = input('Olá qual o seu nome?')
How to run something if the user takes longer than a certain amount of time to respond to input?
Example:
Você demorou demais
.7
The function
signal.alarm
is only available for Unix environment.
You can use the module signal
. First, we have defined a function that will treat the case of the user being inactive and their time expiring. To make it simple, I will just fire an exception:
def timeout():
raise Exception('Seu tempo acabou!')
Finally, the magic. With the module signal
, we define a time signal in which the function timeout
will be 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 running 5 seconds, the function timeout
will be executed; we try to read the user name and, if successful, we 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 function timeout
will be executed, firing the exception and consequently being captured by try
, waxing the program.
The complete code would be:
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 on 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
Thus, 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 in other situations, such as downloading a file with the module requests
:
@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 module multiprocessing
, defining a distinct process to perform the task. Similarly to earlier, 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 on Repl.it | Github GIST
Note that as the function will be executed in another process, the exception that is triggered when time expires does not influence the original process, so to circumvent this, I returned the exception instance itself and did the type check before treating the variable value.
1
I had this doubt a while ago. 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: ")
Look, to be quite honest, I couldn’t decide whether I like this solution or not, but I left my vote for the fact that it is functional and for many applications it would be feasible to apply it for simplicity. Although it is still necessary to put that there is the question of the command Ctrl+C
not stop running the program during this waiting time. You are altering the application’s natural behavior and this can generate side effects. You could add this to the answer?
The program for execution if it is in the console.
Browser other questions tagged python
You are not signed in. Login or sign up in order to post.
Dude, sensational, this designer turned into a Swiss army knife +1. Note: Signal is not fully compatible with all systems, at least not with Windows. Something that might work for Windows would be https://docs.python.org/3/library/threading.html#threading.Timer
– Guilherme Nascimento