Python ยท errors

Exceptions

What Python does when something goes wrong, the errors you will meet most often, and how to raise your own.

Common exceptions: ValueError


          # ValueError - invalid value
          try:
              int("abc")
          except ValueError:
              print("Cannot convert to int")
        

Right type (a string), but a value int() cannot convert.

Common exceptions: TypeError


          # TypeError - wrong type
          try:
              "2" + 2
          except TypeError:
              print("Type mismatch")
        

A string and an int cannot be added.

Common exceptions: KeyError


          # KeyError - missing key
          try:
              d = {"a": 1}
              value = d["b"]
          except KeyError:
              print("Key not found")
        

Common exceptions: IndexError


          # IndexError - invalid index
          try:
              lst = [1, 2, 3]
              value = lst[10]
          except IndexError:
              print("Index out of range")
        

Common exceptions: AttributeError


          # AttributeError - no attribute
          try:
              x = 5
              x.append(1)
          except AttributeError:
              print("Attribute not found")
        

An int has no append method.

File exceptions


        # FileNotFoundError
        try:
            with open("missing.txt") as f:
                pass
        except FileNotFoundError:
            print("File not found")
        # PermissionError
        try:
            with open("/root/file.txt", "w") as f:
                pass
        except PermissionError:
            print("Permission denied")
      

The file does not exist, or it exists but you are not allowed to open it that way.

Raising exceptions


        # raise an exception
        def validate_age(age):
            if age < 0:
                raise ValueError("Age cannot be negative")
            return age
      

raise stops the function immediately; nothing after it runs.

How an exception travels up the call stack


          def validate_age(age):
              if age < 0:
                  raise ValueError(
                      "Age cannot be negative")
              return age
          def register(age):
              return validate_age(age)
          try:
              register(-5)
          except ValueError as e:
              print("Rejected:", e)
        
call with

No matching except in a function? It is abandoned and the exception moves on to its caller.

Re-raising exceptions


          # re-raise same exception
          try:
              result = 10 / 0
          except ZeroDivisionError:
              print("Logging error...")
              raise
        

A bare raise inside except sends the same exception on up, after you have logged it.

Exercises

Which exception, if any?

Exercise 1


        # ValueError when?
        int("3.14")
        # ans: ValueError
      

Exercise 2


        # TypeError example?
        len(5)
        # ans: TypeError (int has no len)
      

Exercise 3


        # KeyError vs get?
        d = {"a": 1}
        d["b"]
        # ans: KeyError
        d.get("b")
        # ans: None
      

Exercise 4


        # IndexError negative?
        lst = [1, 2]
        lst[-10]
        # ans: IndexError
      

Exercise 5


        # NameError?
        print(undefined_variable)
        # ans: NameError
      

Exercise 6


        # ZeroDivisionError?
        5 / 0
        # ans: ZeroDivisionError
        5 // 0
        # ans: ZeroDivisionError
      

Exercise 7


        # raise with message?
        raise ValueError("Custom message")
        # ans: raises with message
      

Exercise 8


        # raise without exception?
        try:
            raise
        except:
            pass
        # ans: RuntimeError (no active exception)
      

A bare raise needs an exception being handled; here there is none, so Python raises RuntimeError, which the bare except then swallows.

Exercise 9


        # exception hierarchy?
        try:
            x = 1 / 0
        except Exception:
            print("Caught")
        # ans: catches ZeroDivisionError
      

Exercise 10


        # assert raises what?
        assert False, "Message"
        # ans: AssertionError: Message
      

Remember

Name the mistake

ValueError bad value, TypeError wrong type, KeyError missing key, IndexError bad position, AttributeError no such attribute, NameError unknown name.

Exceptions travel up

An exception leaves each function until some try has a matching except; if none does, the program stops with a traceback.

raise

Raise your own with a message; a bare raise in an except re-raises the current one.

except Exception

Catches almost everything, because most exceptions inherit from Exception.