Reputation: 28470
I wrote this code to continually ask for more input, if the input is not an integer. However, when I try to abort it in the python interactive session, it keeps asking for input.
Why does it do this, even though I'm pressing Ctrl+C, which means abort.
def get_size(text):
while True:
try:
i = int(input(text))
if i >= 0 and i<24:
break
except:
pass
return i
a = get_size("Input: ")
Upvotes: 2
Views: 2418
Reputation: 152557
When you press Ctrl + C the Python interpreter catches the interrupt and throws a KeyboardInterrupt
exception. Because your bare except
is equivalent to except BaseException
and KeyboardInterrupt
is a subclass of BaseException
your except
will catch the KeyboardInterrupt
. You have no exception handling (like re-raising) in the except
block so the program will continue.
At the very least change the except
to an except Exception
because the exceptions that are subclasses of BaseException
but don't subclass Exception
(KeyboardInterrupt
, SystemExit
, and GeneratorExit
) are not really meant to be swallowed. In some rare cases it makes sense to catch them and do some clean-up before you re-raise them. But there's almost never a use-case for catching them and not raising them again.
The Python documentation actually contains a hierarchy visualization of built-in exceptions that might be handy:
BaseException +-- SystemExit +-- KeyboardInterrupt +-- GeneratorExit +-- Exception +-- StopIteration +-- StopAsyncIteration +-- ArithmeticError | +-- FloatingPointError | +-- OverflowError | +-- ZeroDivisionError +-- AssertionError +-- AttributeError +-- BufferError +-- EOFError +-- ImportError | +-- ModuleNotFoundError +-- LookupError | +-- IndexError | +-- KeyError +-- MemoryError ...
You may notice that except Exception
could also catch some exceptions that you probably cannot recover from. For example MemoryError
, SyntaxError
, or SystemError
normally indicate that something went (really) wrong and these shouldn't be swallowed because these may not be "recoverable" (at least in most cases).
That means you should observe which Exceptions could be thrown by your code and under which circumstances and then decide which ones you can recover from.
In your case:
input()
is not supposed to fail, so you might as well put it outside the try
. try
block. Because you only want that code to run if the try
succeeded you need to guard it, for example in the else
block of the try
. int()
can fail because of a TypeError
in case it's an unsupported type, however input
always returns a string. String is an acceptable type for int()
so one wouldn't expect that to happen.ValueError
. It is thrown if the string couldn't be interpreted as integer.So I would use:
def get_size(text):
while True:
input_text = input(text)
try:
i = int(input_text)
except ValueError:
pass
else:
if 0 <= i < 24:
return i
Or in case you don't want the else
block, you could also continue
in the except
block:
def get_size(text):
while True:
input_text = input(text)
try:
i = int(input_text)
except ValueError:
continue
if 0 <= i < 24:
return i
Which one you use is mostly a matter of preference. Both should work identical.
To summarize it:
try
block.except:
or except BaseException:
. The only exception is if you really want to catch SystemExit
, KeyboardInterrupt
or GeneratorExit
and know how to deal with them appropriately. You may get away with except Exception
, but for any code that you want to use regularly (or in production code) you should invest the time to find the more appropriate exceptions.Upvotes: 4
Reputation: 795
You made the try:
except:
block inside while
loop. So whenever the script throwing an error the except
is just passing and going back to while
loop.
Upvotes: 0
Reputation: 44830
Ctrl+C means KeyboardInterrupt
, but your except
block catches and ignores it (as well as all other exceptions). Even Ctrl+D doesn't stop the execution, so you should just kill the process, to my mind.
Upvotes: 1