Alok
Alok

Reputation: 10654

What happens exactly internally when I terminate my Python script using Ctrl+c?

These days I am learning Python's Exception handling features deeply. I encountered exception SystemExit. While reading about this from official Python Docs I got question in mind that what exactly would have happen when I terminate Python script by pressing Ctrl+c?

lets take this sample code:

def func1(a,b):
    print "func1: "+str(a/b)
    #some more functions

def func2(a,b):
    print "func2: "+str(a/b)
    #some more functions

if __name__=="__main__":
    import random

    count=0
    for i in range(1000000):
            count=count+1
            print "count: "+str(count)
            try:
                    func1(random.randint(-2,3),random.randint(-2,3))
            except KeyboardInterrupt:
                    raise
            except:
                    print "error in func1"
            try:
                    func2(random.randint(-2,3),random.randint(-2,3))
            except KeyboardInterrupt:
                    raise
            except:
                    print "error in func2"

            print "\n"

In this sample code I am catching KeyboardInterrupt so I can stop my script by pressing Ctrl+c. Should I catch SystemExit too to make this code more mature? if yes then why? actually this question is source of my main question which appear on title. so don't consider that I am asking two different question in one post.

Upvotes: 4

Views: 218

Answers (4)

moooeeeep
moooeeeep

Reputation: 32542

You usually not need to catch SystemExit as it is what makes exit() and sys.exit() functions work:

sys.exit([arg])

Exit from Python. This is implemented by raising the SystemExit exception, so cleanup actions specified by finally clauses of try statements are honored, and it is possible to intercept the exit attempt at an outer level.

Example:

try:
    exit()
except SystemExit:
    print "caught"

Therefore, you usually don't want to catch all exceptions in the first place (by using an empty except: clause). The best approach is generally to make your exception handlers as specific as possible. It otherwise makes debugging your application exceptionally hard, as it either hides errors entirely or at least makes it hard to diagnose the details.

Upvotes: 4

Steve Jessop
Steve Jessop

Reputation: 279415

If you're uncertain what exceptions the code you're calling throws to indicate errors then you should (in order of preference):

  1. Find out what it is documented to throw and only catch that
  2. catch Exception, not everything.

Neither KeyboardInterrupt nor SystemExit is a subclass of Exception, but all of the standard Python exceptions used to indicate errors are.

Upvotes: 1

glglgl
glglgl

Reputation: 91149

Your title says something different than the body of your question.

  1. To the title:

    What happens internally is that python captures the SIGINT and raises a KeyboardInterrupt exception from it.

  2. To the text:

    You don't want to do except:.

    Instead, you want

    if __name__=="__main__":
        try:
            import random
    
            count=0
            for i in range(1000000):
                    count=count+1
                    print "count: "+str(count)
                    try:
                            func1(random.randint(-2,3),random.randint(-2,3))
                    except Exception, e:
                            print "error in func1", e # or something...
                    try:
                            func2(random.randint(-2,3),random.randint(-2,3))
                    except Exception, e:
                            print "error in func2", e # or something...
    
                    print "\n"
    except Exception: 
        raise # any other "normal" exception.
    except: # Here it is ok, as you handle most exceptions above.
        pass
    

Most "normal" exception which should normally be handled derive from Exception. Those which have an internal meaning and should normally not be caught (except on global level) don't derive from Exception.

These are KeyboardInterrupt, SystemExit and GeneratorExit.

Upvotes: 1

poke
poke

Reputation: 388383

The only exception your functions can raise is a ZeroDivisionError, so you should only catch that one:

import random

if __name__ == "__main__":
    for count in range(1000000):
        print "count:", count

        try:
            func1(random.randint(-2, 3),random.randint(-2, 3))
        except ZeroDivisionError:
            print "error in func1"

        try:
            func2(random.randint(-2, 3),random.randint(-2, 3))
        except ZeroDivisionError:
            print "error in func2"

        print "\n"

Upvotes: 1

Related Questions