Python3: Why does an exception needs explicit conversion while printing the message - python-3.x

class MyException(Exception):
def __str__(self):
return self.args[0]
def DoWork():
raise MyException("My hoverboard is full of eels")
pass
if __name__ == '__main__':
try:
DoWork()
except MyException as ex:
print("This will get printed: " + str(ex)) #Line1
print("This will not get printed and will raise exception: " + ex) #Line2
Why does an exception needs an explicit conversion in line 1. Ideally it should work as shown in Line2.
Note: I have tried both - the removal of str from MyException class and addition of str; neither of them worked.
Please help.

You have to convert it to a string because x + y ends up calling x.__add__(y), so when x is a string you call str.__add__, which operates on two strings, not on a string and an Exception. Python's built in operators and types generally don't automatically try to force things to be the right type (like javascript, for example), you have to be explicit. This is no different to having to use int() in x = 1 + int("12"), for example.
Note that if you don't want to use str(), you can use % formatting:
print("This will also work: %s" % ex)

Related

Unexpected behavior of JAX jax.lax.switch

i'm seeing an unexpected behavior in jax.lax.switch.
def fun_a():
print('a')
def fun_b():
print('b')
def fun_c():
print('c')
functions_list=[fun_a,fun_b,fun_c]
and then calling
jax.lax.switch(0,functions_list)
returns
a
b
c
I would expect to see only "a" printed.
It is because printing is a side effect and you may have unexpected errors by switch it. You have more information in Jax FAQ with an example where print fails a jax.grad.
In your case your functions should return the values you want to print. However the strings are not valid jax type and only numerical values are supported by switch. For instance you can try something like:
def fun_a():
return ord('a') # convert 'a' to int (= 97)
def fun_b():
return ord('b')
def fun_c():
return ord('c')
functions_list = [fun_a, fun_b, fun_c]
out = jax.lax.switch(0, functions_list)
print(chr(out)) # 'a'
This is expected behavior given the way the JAX compiler works: it expects Pure functions, and your functions are not pure because printing is a side-effect.
If you want printing that behaves as expected within transformed JAX functions, you can use jax.debug.print. For example:
import jax
def fun_a():
jax.debug.print('a')
def fun_b():
jax.debug.print('b')
def fun_c():
jax.debug.print('c')
functions_list=[fun_a,fun_b,fun_c]
jax.lax.switch(0,functions_list)
Output:
a

Finally block is not executed in this code

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

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?>

Python 3: best way to implement your own type with constraints

I'm doing a Python 3 based data conversion and certain character based fields I operate on have specific character allowances and length constraints applied to them.
I'd want to have some sort of swappable/configurable constraint function I roll myself that I could call.
Can you extend str?
Is it best to define a class for this and make variables implementations of that class.
Or are there simpler ways to do this with Python 3?
I'm wondering if anyone can give me pointers as to what to Google for inspiration?
(My initial thoughts are to look at SQLAlchemy's internal code for inspiration for things like Column).
EDIT: SQLAlchemy's code is too sophisticated for this scenario!
For example a type that only allows:
alphanumerics (upper+lowercase)
numerics
plus a selection of special characters.
This may vary by field, but some may use same function.
Hence desire to create custom re-usable types.
I'll do character stripping or substitution.
Then one may only allow 50 chars, whilst another may allow 500 etc.
I'll pass back a tuple with original value, converted value, a boolean to indicate truncation occurred
This is what I ended up with:
valobj.py
import utils
class UDT:
def __init__(self, converter, maxlen, value):
if utils.getClassName(converter) != 'function':
raise TypeError(f'converter {converter} is not a function')
if int(maxlen) <= 0:
raise TypeError(f'maxlen {maxlen} must be 1 or more')
if utils.getClassName(value) != 'str':
raise TypeError(f'value {value} is not a Python String')
self.converter = converter
self.maxlen = int(maxlen)
self.value = value
def convert(self):
intermed = self.converter(self.value)
truncated = len(intermed) > self.maxlen
result = intermed[:self.maxlen] if truncated else intermed
return (result, truncated, self.value)
class Job:
def __init__(self, name):
self._name_tuple = UDT(utils.fix_chars, 64, name).convert()
utils.py
import string
def getClassName(arg):
return(str(type(arg)).replace("<class '","").replace("'>",""))
def fix_chars(text) -> str:
result = ''
for c in text:
if ( (string.ascii_letters.find(c) != -1)
or (string.digits.find(c) != -1)
or ('._-#'.find(c) != -1)
):
result += c
else:
result += '_'
result = tidy_up_str(result)
return (result)
def tidy_up_str(text) -> str:
result = text
result = result.replace('_-_', '_')
while result.find('__') != -1:
result = result.replace('__', '_')
if result.endswith('_'):
result = result[:-1]
return result

Best way to handle exceptions in functon args?

I was recently coding a few Python 3.x programs and I wonder what is the best way of handling simple exceptions in python function args. In this example I'm going with checking if inserted value can be converted to int. I've come up with two ways of doing this:
def test_err_try(x, y, z):
try:
int(x)
int(y)
int(z)
except ValueError or TypeError: #try handler
return 'Bad args.'
##code##
or
def test_err_if(x, y, z):
if type(x) != int or type(y) != int or type(z) != int: #if handler
raise ValueError('Bad args.')
else:
##code##
I know that there is a difference in what the handlers are returning - in the first case it's just string 'Bad args.' and in the second it is ValueError exception.
What is the best (or rather simplest and shortest) way? First, second or neither and there is a better one?
The answer depends on your use case. If you are building a function which will be exposed to an end user, then the try except block offers more functionality because it will allow any variable which can be converted to an int. In this case I would suggest raising an error rather than having the function return a string:
try:
x = int(x)
y = int(y)
z = int(z)
except ValueError:
raise TypeError("Input arguments should be convertible to int")
If the function is meant for internal use within your program, then it is best to use the assert statement because its evaluation can be disabled once you are finished debugging your program.
assert type(x) is int
assert type(y) is int
assert type(z) is int

Resources