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
Related
I have a for loop which loops through initial guesses for a scipy.optimize.minimize routine. Some of the initial guesses fail, so I want to wrap the call to scipy.optimize.minimize in a try/except statement, so that when a guess fails, it moves on to the next.
Unfortunately this is not working. Once a guess fails, the next iterations also fail, even if the initial guess is a good one that I know works.
When I try to reproduce this failure in a MWE, I can't, so I am stumped.
Here is the MWE that works
import numpy as np
def f(x):
assert type(x) == float
return np.log(x)
def arbitrary_function():
vals = [ 0.5, "string", 5, 9.3]
v_list=[]
for num in vals:
try:
v = f(num)
if v > 0:
v_list.append(v)
except:
print("failed on {}".format(num))
continue
return v_list
my_list = arbitrary_function()
print(my_list)
Am I missing something with the try.. except usage?
The error that the real code raises on the failed attempts is due to
assert np.isclose(np.sum(x_tilde), 1.0)
AssertionError
for this reason I included the assert type(x) == float in the MWE, it raises the same exception, however, it carries on fine after hitting string, whereas my actual code only does the exceptions following a failure.
The real code has inside the try statement, where I have f(num)
try:
params = scipy.optimize.minimize(stuff)
if params.success:
stuff
except:
continue
Maybe the params.success is throwing it off since that doesn't exist when the scipy.optimize.minimize fails in the middle?
It does not appear to even attempt to do scipy.optimize.minimize on the next iteration once one of the initial guesses has caused scipy to fail.
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
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?>
Edited version
x = input("Put 'thing' here \n")
if x is 'thing':
print("Success thingx!")
else:
print(x)
y = "thing"
if y is 'thing':
print("Success thingy!")
else:
print(x)
While I expected my result to be
Put 'thing' here
thing
#above is the input
Success thingx!
Success thingy!
I got the result
Put 'thing' here
thing
#above is the input
thing
Success thingy!
Is there an error in how I am writing this?
the is operator checks for identity. cpython use string interning to use the same str objects in different places. But, when using the input method a new str object is created and not the interned one
is => id(x1) == id(x2)
adding some id prints
x = str(input("Put 'thing' here \n"))
print('x', id(x))
print('thing', id('thing'))
if x is 'thing':
print("Success thingx!")
else:
print(x)
y = str("thing")
print('y', id(y))
if y is 'thing':
print("Success thingy!")
else:
print(x)
then the output is
thing
x 42666048
thing 42737760
thing
y 42737760
Success thingy!
you should use == if you want to test for equality
you're confusing is with ==
The is operator checks exact identity, that the two objects are actually the same exact object. This is implementation-specific and often the case for interned strings (small string literals) in cpython. The return value of input() is dynamically constructed and doesn't participate in interning here.
You want to use == to check equality between strings. Reserve is for singletons such as True, False, None, ... (Ellipsis), NotImplemented, types, etc.
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)