Charles Charles - 1 month ago 8
Python Question

Functions decorator safety in python

How this code works? It is from chapter 8 in "Data Science by Scratch" from the gradient. Why do I need to wrap a function inside another fucntion? Is there a more readable way to achieve this execption handling? Here's the explanation for it.


It is possible that certain step sizes will result in invalid inputs for our function. So we’ll need to create a “safe apply” function that returns infinity (which should never be the minimum of anything) for invalid inputs:


def safe(f):
"""return a new function that's the same as f,
except that it outputs infinity whenever f produces an error"""
def safe_f(*args, **kwargs):
try:
return f(*args, **kwargs)
except:
return float('inf')
return safe_f

Answer

Lets say we have a trivial function like this:

def myfunc(n):
    return 42/n

and we do this:

print(myfunc(0))

We get this:

Traceback (most recent call last):
  File "gash.py", line 14, in <module>
    print(myfunc(0))
  File "gash.py", line 12, in myfunc
    return 42/n
ZeroDivisionError: division by zero

Now we do this:

myfunc = safe(myfunc)
print(myfunc(0))

We get this:

inf

The second time we call safe() which returns a new function with the embedded exception handling. We replace what the name "myfunc" refers to, now it refers to the returned function. The original myfunc is not lost, it is called f inside the new one.

A @safe decorator is essentially doing the same thing as myfunc = safe(myfunc)