How to check if tuple has element? - python

I have an exception from which I'm trying to get args, but if fails.
print hasattr(e, 'args')
print type(e.args)
print hasattr(e.args, '1')
print hasattr(e.args, '0')
print '1' in e.args
print '0' in e.args
print 1 in e.args
print 0 in e.args
print e.args[0]
print e.args[1]
This prints:
True
<type 'tuple'>
False
False
False
False
False
False
Devices not found
4

You simply use the in operator:
>>> try:
... raise Exception('spam', 'eggs')
... except Exception as inst:
... print inst.args
... print 'spam' in inst.args
...
('spam', 'eggs')
True
If your code is returning False then most likely 1 wasn't an argument to the exception. Perhaps post the code where the exception was raised.
You can check if the tuple has positions 0 to N by doing len.

You can check the length of your tuple:
t = 1, 2, 3,
if len(t) >= 1:
value = t[0] # no error there
...or you can just check for an IndexError, which I'd say is more pythonic:
t = 1, 2, 3,
try:
value = t[4]
except IndexError:
# handle error case
pass
The latter is a concept named EAFP: Easier to ask for forgiveness than permission, which is a well known and common Python coding style.

Related

Is there a way to print the assert error message inside a except block?

I am practicing with error handling and I have a question. can you make it so the error messages in the assert will be displayed in the except block right now if a error occurs only 'error' is printed and not the actual error message
try:
a = int(input('Please enter the first number it must be >= 200' + '\n' + '(note the sum of both numbers must be <=300)'))
b= int(input('please your second number it must be <= 50'))
c = a + b
assert a >=200 and isinstance(a, int), 'invalid entry for a must be <= 200 and a number'
assert b<=50 and isinstance(b, int), 'invalid entry for b must be <=50 and a number'
assert c <= 300, 'The sum of your numbers is >300'
except ValueError
print('error')
else:
print('All in range')
Add an except that catches the AssertionError and prints it:
except AssertionError as e:
print(e.args[0] if e.args else "error")

Raising an exception during for loop and continuing at next index in python

I've been breaking my head all day, and I cannot seem to solve this. I'm supposed to write an Exception class then raise it during an iteration and continue where I left off.
class OhNoNotTrueException(Exception):
"""Exception raised when False is encountered
Attributes:
message -- explanation of the error"""
def __init__(self, value):
self.value = value
am_i_true_or_false = [True, None, False, "True", 0, "", 8, "False", "True", "0.0"]
try:
for i in am_i_true_or_false:
if i is False:
raise OhNoNotTrueException(i)
continue #<--this continue does not work
else:
print(i, "is True")
except OhNoNotTrueException as e:
print(e.value, "is False")
However, I can't get the iteration back to the last index, even after putting continue. I'm not sure if this is the only way to do it, but I'm breaking my head over here. Anyone want to take a crack at it?
I'm supposed to get the following output:
True is true.
None is false
False is false
True is true.
0 is false
is false
8 is true.
False is true.
True is true.
0.0 is true.
Everything after the exception is raised will never be reached, and you will be taken outside the loop, as if everything in the try-block had never happend. Thus, you need to try/except inside the loop:
In [5]: for i in am_i_true_or_false:
...: try:
...: if i is False:
...: raise OhNoNotTrueException(i)
...: else:
...: print(i, "is not False")
...: except OhNoNotTrueException as e:
...: print(e.value, "is False")
...:
True is not False
None is not False
False is False
True is not False
0 is not False
is not False
8 is not False
False is not False
True is not False
0.0 is not False
Notice what happens if your try-block contains the loop:
In [2]: try:
...: for i in am_i_true_or_false:
...: if i is False:
...: raise Exception()
...: else:
...: print(i,"is not False")
...: except Exception as e:
...: continue
...:
File "<ipython-input-2-97971e491461>", line 8
continue
^
SyntaxError: 'continue' not properly in loop
You should do the loop outside of the try/except block. Then one individual list entry will be checken by the try catch and afterwards the loop will continue with the next one:
for i in am_i_true_or_false:
try:
if i is False:
raise OhNoNotTrueException(i)
else:
print("{} is True".format(i))
except OhNoNotTrueException as e:
print("{} is False".format(e.value))
The way you are doing it, the loop is executed until the first exception and then the except block is executed and the program ends. The continue is not reached in this case because you threw an exception which will be caught in the except block.

What is the best way to return a stack variable from a recursive function?

I have a situation where I need to return the first item found in a list, How do I return it when I use recursion ?:
def get_hostname (ifname):
try :
# Do something to get hostname
return hostname
except IOError:
return -1
def get_hostname_r(lst):
if not lst:
return False
if get_hostname(lst[0]) != -1 :
print 'Found ', get_hostname(lst[0])
return get_hostname(lst[0]) # DOESNT WORK
else :
print 'Not found ', get_hostname(lst[0])
get_hostname_r(lst[1:])
print 'return = ', get_hostname_r(['eth1','eth2','eth3','eth4','eth5' ])
I understand that the return goes back to the calling stack but Iam looking here for the best practices without using a global variable to get the value?
You can simply return the value, the returned value is handed over the whole recursion stack:
def get_hostname_r(lst):
if not lst:
return False
if get_hostname(lst[0]) != -1 :
print 'Found ', get_hostname(lst[0])
return get_hostname(lst[0])
else:
print 'Not found ', get_hostname(lst[0])
return get_hostname_r(lst[1:])
But easier to read is a for-loop:
def get_hostname_r(interfaces):
for interface in interfaces:
result = get_hostname(interface)
if result != -1:
return result
return False
First, if you can't do anything about the IO error, don't mask it by returning -1 ("What does -1 mean? Why didn't I get a host name back?"). Just document that get_hostname might raise an IOError.
def get_hostname(ifname):
# Do stuff that might raise an IOError
return hostname
The same goes for the recursive version. Either return a valid hostname, or raise an exception (or let an uncaught exception continue).
def get_hostname_r(lst):
if not lst:
raise IOError("Hostname not found")
try:
hostname = get_hostname(lst[0])
print >>sys.stderr, 'Found {0}'.format(hostname)
return hostname
except IOError:
print 'Not found with {0}'.format(lst[0])
return get_hostname_r(lst[1:])
Of course, recursion isn't really the best way to write this; use a simple for loop instead to iterate over lst.
def get_hostname_iter(lst):
for ifname in lst:
try:
return get_hostname(ifname)
except IOError:
continue
raise IOError("Hostname not found")

This tutorial on raising exceptions. I cant figure it out?

The instructions: Write a function validate_input(string) which takes a command string in the format 'command arg1 arg2' and returns the pair ('command', [arg1, arg2]), where arg1 and arg2 have been converted to floats. If the command is not one of 'add', 'sub', 'mul', or 'div', it must raise InvalidCommand. If the arguments cannot be converted to floats, it must raise InvalidCommand.
Typical inputs and outputs:
validate_input('add 2 3') -> ('add' [2. , 3.])
validate_input('hahahaha 2 3') -> Raises InvalidCommand()
validate_input('add six 3') -> Raises InvalidCommand()
Here is my code:
class InvalidCommand(Exception):
pass
def validate_input(string):
"""
validate_input(str) -> (str, [float])
If string is a valid command, return its name and arguments.
If string is not a valid command, raise InvalidCommand
Valid commands:
add x y
sub x y
mul x y
div x y
Arguments x and y must be convertable to float.
"""
# your code here
inlist = string.split(' ')
commands = []
strdigits = []
floats = []
output = []
for x in inlist:
if x.isdigit():
strdigits.append(x)
else:
commands.append(x)
for x in commands:
try:
x == 'add' or x == 'sub' or x == 'mul' or x == 'div'
output.append(x)
except ValueError:
raise InvalidCommand(ValueError)
for x in strdigits:
try:
float(x)
floats.append(float(x))
except ValueError:
raise InvalidCommand(ValueError)
output.append(floats)
return tuple(output)
When I test it on the values where it is supposed to raise InvalidCommand(), It tells me "Your code must raise InvalidCommand(). But my code does. I checked for typos and there are not any. So did I do the whole raising statement wrong? Please show me how to fix this. Thanks.
This line:
x == 'add' or x == 'sub' or x == 'mul' or x == 'div'
does nothing. It does not actually do anything with the result of your test, certainly it does not raise ValueError.
What you need is something like this:
if x.lower in ('add', 'sub', 'mul', 'div'):
output.append(x)
else:
raise InvalidCommand('unknown command: {}'.format(x))
Your code works for the numeric arguments because float() can raise ValueError if it is given a string that can not be converted to a float:
>>> float('abcd')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: could not convert string to float: abcd
Also, why you are passing ValueError as an argument to your custom exception? You might like to pass an error string that describes the nature of the error, e.g.
raise(InvalidCommand('arguments must be numeric: {}'.format(x))
or, you can pilfer ValueError's message:
try:
float(x)
floats.append(float(x))
except ValueError as exc:
raise InvalidCommand(exc)
You're making this way more complicated than it needs to be.
class InvalidCommand(Exception):
pass
def validate_input(datastr):
"""
validate_input(str) -> (str, [float])
If string is a valid command, return its name and arguments.
If string is not a valid command, raise InvalidCommand
Valid commands:
add x y
sub x y
mul x y
div x y
Arguments x and y must be convertable to float.
"""
inlist = datastr.split()
if len(inlist) != 3:
raise InvalidCommand('Bad command length: ' + str(len(inlist)))
x = inlist[0]
if x in ('add', 'sub', 'mul', 'div'):
cmd = x
else:
raise InvalidCommand('Bad command verb: ' + x)
floats = []
for x in inlist[1:]:
try:
floats.append(float(x))
except ValueError:
raise InvalidCommand('Bad command arg: ' + x)
return cmd, floats
#Test
data = [
'add 1 2',
'sub 3.0 2.0',
'mul 4.5 1.5',
'div 8 4',
'add 1 2 3',
'fred 2 3',
'add a b',
'sub 1 c',
]
for s in data:
try:
print(validate_input(s))
except InvalidCommand as e:
print(repr(s), e)
output
('add', [1.0, 2.0])
('sub', [3.0, 2.0])
('mul', [4.5, 1.5])
('div', [8.0, 4.0])
'add 1 2 3' Bad command length: 4
'fred 2 3' Bad command verb: fred
'add a b' Bad command arg: a
'sub 1 c' Bad command arg: c
I've changed the parameter of the validate_input function because string is the name of a standard Python module, so it can be confusing to use it for a simple variable name. And if you want to use that module then shadowing its name like that can lead to annoying bugs.
I did the same question for my uni subject csse1001. What I did was this:
# your code here
lst = string.split(' ')
commands = ['add', 'sub', 'mul', 'div']
if lst[0] not in commands:
raise InvalidCommand()
if len(lst) != 3:
raise InvalidCommand()
try:
arg1 = float(lst[1])
arg2 = float(lst[2])
return(lst[0], [arg1, arg2])
except ValueError:
raise InvalidCommand()
This worked for me.

Python run something only if exception is met

I want to run a line of code if any of the exceptions are met, but not if the try succeeds, a bit like the opposite of else when using try/except.
Currently I have exceptionOccured to set to True if an exception occurs, but I'm guessing there should be a more pythonic way of doing this.
Here's the current code I have, it was an attempt to edit values in a dictionary from a list, and create the keys if they don't exist. How would I redo the exceptions so that exceptionOccured is not needed?
dictionaryValue = {"data": dict.fromkeys( [0, 1, 2, 3] ), "data2": {0: "test",1:"test2"}}
reducedDictionary = dictionaryValue
valueList = ["data", 1, 64, "Testing", "value"]
canOverwriteKeys = True
for i in valueList[:-2]:
exceptionOccured = False
try:
if type( reducedDictionary ) != dict:
raise ValueError()
elif reducedDictionary.get( i, False ) == False:
raise KeyError()
except ValueError:
print "not dictionary"
reducedDictionary = {}
exceptionOccured = True
except KeyError:
print "key doesn't exist"
exceptionOccured = True
if exceptionOccured or ( type( reducedDictionary[i] ) != dict and canOverwriteKeys ):
print "setting key value"
reducedDictionary[i] = {}
reducedDictionary = reducedDictionary[i]
reducedDictionary[valueList[-2]] = valueList[-1]
print dictionaryValue
Edit: Improved the code based on the answers, thanks :)
def editDictionary( dictionaryName, listOfValues, canOverwriteKeys=True ):
reducedDictionary = dictionaryName
for i in valueList[:-2]:
if type( reducedDictionary ) != dict:
reducedDictionary = {}
try:
if reducedDictionary.get( i, False ) == False:
raise ValueError()
elif type( reducedDictionary[i] ) != dict:
if not canOverwriteKeys:
return
raise KeyError()
except( ValueError, KeyError ):
reducedDictionary[i] = {}
except:
print "Something went wrong"
return
reducedDictionary = reducedDictionary[i]
reducedDictionary[valueList[-2]] = valueList[-1]
Just catch both exceptions in one handler:
try:
# ...
except (ValueError, KeyError) as e:
if isinstance(e, ValueError):
print "not dictionary"
reducedDictionary = {}
else:
print "key doesn't exist"
print "setting key value"
reducedDictionary[i] = {}
If your exception handlers are more complex, you could also use a function:
def handle_common_things():
# things common to all exception handlers
try:
# ...
except Exception1:
# do exception-specific things
handle_common_things()
except Exception2:
# do exception-specific things
handle_common_things()
I'd probably go with Martijn's answer, but you can also wrap your try/except block in another layer of try/except (and in real code I'd frown on using a bare except like this, or more likely define a new exception that's thrown from inside any except: clauses that you want to detect)
def exception_test(val):
try:
try:
result = 1.0 / val
except ZeroDivisionError:
print "Divide by zero"
raise
else:
print "1 / {0} = {1}".format(val, result)
except:
print "there was an exception thrown."
>>> exception_test(2.0)
1 / 2.0 = 0.5
>>> exception_test(0)
Divide by zero
there was an exception thrown.

Categories