Finally block is not executed in this code - python-3.x

The finally block in this code doesn't execute at all.
I have wrote this code to prevent assigning a None value to the current object, so I came up with an idea to use finally and assign this object with the previous state, but when I execute it the finally block doesn't execute at all (I have added a print statement to see if it's executed and it's not).
def __idiv__(self, other):
try:
if other is None:
raise ValueError('The second number is None')
if not isinstance(other, Complex):
other = Complex(other)
den = other * other.con()
num = self * other.con()
re = num.re / den.re
im = num.im / den.re
return Complex(re, im)
except (ZeroDivisionError, ValueError) as err:
print(colored('{}: {}'.format(err.__class__.__name__, err), 'red'))
finally:
print('-'*80)
return Complex(self.re, self.im)
When I call this method I just get this without the output of print statement in finally block:
ZeroDivisionError: float division by zero

Related

Python3: Try block won't stop looping after recursive function call via caught exception

I have a function that is a CLI menu for another program I'm working on. Each time the user enters input, the input() function is run within a try block.
If all try blocks succeed without catching any exceptions, there is no issue and the function behaves as expected; the function runs through, return 1 is called and the function ends.
However, when an exception is raised, the user is notified why and then the current function is called recursively. When this occurs and then the user runs through the function, return 1 is once again called, but this time the function immediately returns to the first try block in the function that had raised the exception previously.
The function in question:
def menu_userSetup():
selection = 0; selected_key = 0
if userSettings is None:
userSettings = defaultSettings
refresh_UI('\_ Test Setup _/', py3_version, bash_version, True)
COLS = get_terminal_size().columns
print('\n', 'Current Settings:'.center(COLS))
z = 0
for setting in userSettings:
print('{}. {}: {}'.center(COLS - (COLS // 50)).format(z, setting, userSettings[setting]), end='\r')
z += 1
print('\n', 'Which setting would you like to set?'.center(COLS), end='')
try: selection = int(input('{}'.format(' ' * (COLS // 2))))
except KeyboardInterrupt: EXIT('Detected KeyboardInterrupt..')
except:
print('\n', 'Oops. That input is invalid!'.center(COLS))
t.sleep(1.5)
menu_userSetup()
# the tuple function is used to return the key string according to its unordered index
try: selected_key = tuple(userSettings.items())[selection][0]
except KeyboardInterrupt: EXIT('Detected KeyboardInterrupt..')
except:
print('\n', 'That is not an available option!'.center(COLS))
t.sleep(1.5)
menu_userSetup()
COLS = get_terminal_size().columns
refresh_UI('\_ Test Setup _/', py3_version, bash_version, True)
print('\n', 'Ok, {} selected!'.center(COLS - (COLS // 50)).format(selected_key))
print('Type in your new setting:'.center(COLS))
new_set = input('{}'.format(' ' * (COLS // 2)))
if new_set.find('true') and new_set.find('t') != -1:
new_set = True
elif new_set.find('false') and new_set.find('f') != -1:
new_set = False
if new_set is not None or '':
userSettings[selected_key] = new_set
print('\n', '{} has been set to {}!'.center(COLS - (COLS // 50)).format(selected_key, new_set))
t.sleep(1.5)
else:
print('\n', 'Oops. That input is invalid!'.center(COLS))
t.sleep(1.5)
menu_userSetup()
refresh_UI('\_ Test Setup _/', py3_version, bash_version, True)
COLS = get_terminal_size().columns
print('\n', 'Current Settings:'.center(COLS))
z = 0
for setting in userSettings:
print('{}. {}: {}'.center(COLS - (COLS // 50)).format(z, setting, userSettings[setting]), end='\r')
z += 1
r = input("Press enter to return to the main menu or 'r' to make another change!\n")
if r == 'r':
menu_userSetup()
print('returning...'); t.sleep(2)
return 1
Is it perhaps simply not possible to recursively call a function from an except block?
If it's not, how can I achieve the same effect of catching errors leading to a recursive function call?
Note: This solution does not need to be compatible with python 2.x, but any extra info as a bonus is welcome nonetheless!
Fixed!
The issue seems to be that when return is called from within the function (that has been called from within the exception block), it returns back to the last line of the exception where the function was last called from.
It does not return to the location where the function was first called from initially.
I tried just adding return 1 after the recursive call of the function within the except blocks, and that worked!
try: selection = int(input('{}'.format(' ' * (COLS // 2))))
except KeyboardInterrupt: EXIT('Detected KeyboardInterrupt..')
except:
print('\n', 'Oops. That input is invalid!'.center(COLS))
t.sleep(1.5)
menu_userSetup(); return 1

Is `return` alone equivalent to `return(None)` in Python 3.8?

I just saw the following Python code, and I'm a bit confused by the first return. Does it return None by default? Is it equivalent to return(None)? If the first return is executed, will the function inner() automatically end there and the second return be left alone?
def smart_check(f):
def inner(a,b):
if b==0:
print("illegit: b =", b)
return # the first return
return(f(a,b))
return(inner)
#smart_check
def divide(a,b):
return(a/b)
Does it return None by default? Is it equivalent to return(None)
Yes, see docs: If an expression list is present, it is evaluated, else None is
substituted.
If the first return is executed, will the function inner()
automatically end there and the second return be left alone?
Yes
If you don't want to return anything you can even drop the return statement completely:
def smart_check(f):
def inner(a,b):
if b != 0:
return f(a,b)
print("illegit: b =", b)
return(inner)
As print doesn't return anything you could even rewrite this function as
def smart_check(f):
def inner(a,b):
return f(a,b) if b!=0 else print("illegit: b =", b)
return(inner)

How does Python distinguish if a parameter is default?

a = iter([1])
next(a)
next(a)
raises StopIteration
a = iter([1])
next(a)
next(a, None)
there is no StopIteration
however the defination of nextis
def next(iterator, default=None):
How does Python distinguish if the parameter is default or user-given?
The builtin function next doesn't use None as its default. In fact, as you can see in the C source code (for cpython, the official Python interpreter), its argument handling is very low level. The pure Python equivalent would be using *args in the function definition and and manually checking that you got either one or two arguments. Here's what that might look like:
def next(*args):
assert(1 <= len(args) <= 2)
try:
return args[0].__next__()
except StopIteration:
if len(args) > 1:
return args[1]
else:
raise
A better way to replicate similar behavior in Python is to use a default value that is not possible for outside code to accidentally supply. Here's one good way to do it:
_sentinel = object() # a unique object that no user should ever pass to us
def next(iterator, default=_sentinel):
try:
return iterator.__next__()
except StopIteration:
if default is not _sentinel:
return default
else:
raise

Handling exception returned by a method

I am calling a method that throws Valuerror exception or returns valid response as a string. I am not able to handle the situation if it is an exception. If the return is the valid string I am supposed to slice it and do other things with it.
x = sanitize("245755487")
try:
print(data = x[:3])
except:
print(x)
def sanitize(self,tel):
data = [d for d in tel if d.isalnum()]
digits = int(len(data))
if digits < 10:
raise ValueError("The digit cannot be below 10")
else:
"".join(data)
If the x is subscribable I am supposed to get that string sliced.
You need to place call to sanitize method in try block because sanitize is the method that raises exception. Placing it outside try block makes no sense. You should handle error in except block instead of print(x).
try:
x = sanitize("245755487")
print(data = x[:3])
except ValueError as err:
print(err);
#<what would you like to do if there is an error?>

Why does this code return none

why does the following code returns none:
j = 22
def test(j):
if j > 0:
print('j>0')
else:
print('j<0')
Output:
j>0
None
A function in Python always has a return value, even if you do not use a return statement, defaulting to None
Because the test function doesn't return a value, it ends up returning the object None. that's why it ended up printing None Since you do not have a return value specified
you may not use print in your function, but return a string instead
def test(j):
if j > 0:
return 'j>0'
else:
return 'j<0'
then call it like this: print it when calling the function
print(test(22))
see answer's here for more detail

Resources