Dynamic Semantic errors in Python
Question: i came across this as an interview question. This question seemed interesting.
So, i am posting it here.

Consider the operation which gives semantic error like division by zero. By
default, python compiler gives output like "Invalid Operation" or something.
Can we control the output that is given out by Python compiler, like print
some other error message, skip that division by zero operation, and carry on
with rest of the instructions?  
And also, how can i evaluate the cost of run-time semantic checks? There are
many python experts here. I am hoping someone will throw some light on this.
Thanks in advance.


Answer: > Can we control the output that is given out by Python compiler, like print
> some other error message, skip that division by zero operation, and carry on
> with rest of the instructions?

No, you cannot. You can manually wrap every dangerous command with a
`try...except` block, but I'm assuming you're talking about an automatic
recovery to specific lines _within_ a `try...except` block, or even completely
automatically.

By the time the error has fallen through such that `sys.excepthook` is called,
or whatever outer scope if you catch it early, the inner scopes are gone. You
can change line numbers with
[`sys.settrace`](http://docs.python.org/2/library/sys.html#sys.settrace) in
CPython although that is **only an implementation detail** , but since the
outer scopes are gone there is no reliable recorvery mechanism.

If you try to use the humorous `goto` April fools module (that uses the method
I just described) to jump blocks _even within a file_ :

    
    
    from goto import goto, label
    
    try:
        1 / 0
        label .foo
        print("recovered")
    
    except:
        goto .foo
    

you get an error:

    
    
    Traceback (most recent call last):
      File "rcv.py", line 9, in <module>
        goto .foo
      File "rcv.py", line 9, in <module>
        goto .foo
      File "/home/joshua/src/goto-1.0/goto.py", line 272, in _trace
        frame.f_lineno = targetLine
    ValueError: can't jump into the middle of a block
    

so I'm pretty certain it's impossible.

* * *

> And also, how can i evaluate the cost of run-time semantic checks?

I don't know what that is, but you're probably looking for a
[`line_profiler`](http://pythonhosted.org/line_profiler/):

    
    
    import random
    
    from line_profiler import LineProfiler
    profiler = LineProfiler()
    
    def profile(function):
        profiler.add_function(function)
        return function
    
    
    @profile
    def foo(a, b, c):
        if not isinstance(a, int):
            raise TypeError("Is this what you mean by a 'run-time semantic check'?")
    
        d = b * c
        d /= a
    
        return d**a
    
    profiler.enable()
    for _ in range(10000):
        try:
            foo(random.choice([2, 4, 2, 5, 2, 3, "dsd"]), 4, 2)
        except TypeError:
            pass
    
    profiler.print_stats()
    

output:

    
    
    Timer unit: 1e-06 s
    
    File: rcv.py
    Function: foo at line 11
    Total time: 0.095197 s
    
    Line #      Hits         Time  Per Hit   % Time  Line Contents
    ==============================================================
        11                                           @profile
        12                                           def foo(a, b, c):
        13     10000        29767      3.0     31.3      if not isinstance(a, int):
        14      1361         4891      3.6      5.1          raise TypeError("Is this what you mean by a 'run-time semantic check'?")
        15                                           
        16      8639        20192      2.3     21.2      d = b * c
        17      8639        20351      2.4     21.4      d /= a
        18                                           
        19      8639        19996      2.3     21.0      return d**a
    

So the "run-time semantic check", in this case would be taking 36.4% of the
time of running `foo`.

* * *

If you want to time specific blocks manually that are larger than you'd use
`timeit` on but smaller than you'd want for a profiler, instead of using two
`time.time()` calls (which is quite an inaccurate method) I suggest [Steven
D'Aprano's Stopwatch context manager](https://code.google.com/p/my-startup-
file/source/browse/timer.py).

