Extending & Embedding Python Using C - Exceptions
Written by Mike James   
Monday, 30 October 2023
Article Index
Extending & Embedding Python Using C - Exceptions
Exception Classes
Raising Exceptions

C doesn't do exceptions but Python does. This means we have to fit in with Python's way of implementing exceptions. This is an extract from the latest title in the I Programmer Library that helps you combine the speed and power of C with the versatility and ease-of-programming of Python.

Extending & Embedding Python Using C

By Mike James

extendPython360

Buy from Amazon.

Contents

       Preface

  1. Extending And Embedding Python
  2. A First C Module Using Linux ***NEW!!!
  3. A First C Module Using Windows
  4. Module Basics
        Extract: A First Module
        Extract: 
    Pi 
  5. Arguments
  6. Returning Python Objects
  7. Objects And Attributes
  8. More Complex Objects – Tuples, Lists and Dicts
  9. Errors, Exceptions And Reference Counting
        Extract:
    Exceptions 
  10. Bytes And Strings
  11. Modules And Attributes
  12. New Types
  13. Advanced Types
  14. Threads And The GIL
  15. Embedding Python

<ASIN:B0CK3X93KF>

Errors, Exceptions And Reference Counting

Once you start using more complex objects you are likely to need to test for conditions like an object having or not having an attribute. You may well have to pass the error back to Python or raise an error condition on your own account. Python implements a sophisticated system of exceptions which make error handling more capable than simply having to give up and post an error code.

In addition, we have to look at ways of checking that our reference counting is working if we want to avoid memory leaks and generating unexpected exceptions.

Exceptions - The Python View

Python implements exceptions to deal with runtime errors. C programmers might not be familiar with the idea of an exception. In C you generally deal with an error by setting an error code, and if you are lucky an error message, and terminating the program. More sophisticated programming languages, such as Python, implement exceptions as a way of avoiding having to terminate the program.

In Python you can write:

try:
  block of code
except
  error handling code

If any instructions in the block of code cannot be completed for any reason an exception is raised and the except clause is activated. This sounds like nothing more sophisticated than an if error then handle error construct, but it is much more. The block of code may call functions and if an exception is raised in one of the functions we have the problem of how to get back to the calling code. What happens is that the call stack is “unwound”. It is as if each function in the call chain is forced to do a return with the extra step of erasing of any return values. What this means is that the effects of any function are obliterated as far as possible and the code in the except clause can run as if the block of code was never even attempted.

Of course, this doesn’t erase any non-local side effects of the function. For example if the function printed something, opened a file or modified a global variable then these things are not automatically undone by the exception.

For example:

total=0
def myFunc(x,y):
    global total
total=total+1
print("in myFunc")
ans=x/y
return ans
try:
myFunc(1,0)
except:
print("Can't divide by zero")
print(total)

If you try this out you will see the error message, but you will also see the result of the print and total will still be incremented. Notice that the exception occurs at ans=x/y and no instructions after this are executed.

As the exception unwinds the call stack it is as if the function was never called. For example, if you add:

print(result)

at the end of the program you will see a runtime error that result doesn’t exist. In principle you can try to call he function again after putting things right. The main purpose of the except clause is to allow you to undo any global changes that the function may have made and to call the function again. For example:

total=0
def myFunc(x,y):
global total
total=total+1
print("in myFunc")
ans=x/y
return ans
try:
result=myFunc(1,0)
except:
print("Can't divide by zero")
total=total-1
result=myFunc(1,1)
print(result)
print(total)

In this case the except decrements total before calling the function again. Notice that now result exists, even if there is an exception. In general, the except clause should undo global changes including closing files, erasing data and so on.

The try/except will respond to any relevant exception from any function called within the try clause.

There may well be a chain of functions called and if one of them raises an exception then its stack frame is removed and the function that called it is examined for a try/except call. If one isn’t found then the next function in the call chain is examined for a try/except. This carries on until a function with try/except is found or there are no more to examine, in which case a runtime error occurs.



Last Updated ( Saturday, 04 November 2023 )