I'm parsing an XML file using Beautiful Soup. Sometimes I have entries that are missing one or more of the keys I'm parsing. I want to setup exceptions to handle this. My code looks something like this:
for entry in soup.findAll('entry_name'):
try:
entry_dict = dict(entry.attrs)
x = entry_dict["x"]
y = entry_dict["y"]
z = entry_dict["z"]
d[x] = [y, z]
except KeyError:
y = "0"
d[x] = [y, z]
The problem is I can have "y", "z" or both "y and z" missing depending on the entry. Is there a way to handle specific KeyErrors? Something like this:
except KeyError "y":
except KeyError "z":
except KeyError "y","z":
You can check for exception arguments:
a = {}
try:
a['a']
except KeyError as e:
# handle key errors you want
if e.args[0] == 'a':
pass
# reraise the exception if not handled
else:
raise
Personally I wouldn't use a try/except here and instead go for the detection approach instead of the handling approach.
if not 'y' in entry_dict.keys() and not 'z' in entry_dict.keys():
# handle y and z missing
elif not 'y' in entry_dict.keys():
# handle missing y
elif not 'z' in entry_dict.keys():
# handle missing z
A slight variation on Paweł Kordowski answer:
a = {}
try:
a['a']
except KeyError as e:
# 2 other ways to check what the missing key was
if 'a' in e.args:
pass
if 'a' in e:
pass
# reraise the exception if not handled
else:
raise
Related
I only want my list to have one element in it. There should be one exception raised if the list is empty and a different exception raised if the list has more than one element.
The following code accomplishes the task, but I don't think it's written as well as it should by any standards out there. Additionally, if the condition is met that the list is greater than one, I want it to print the python error "index out of range" as it does in the other condition. How can I improve upon this?
x = []
try:
if len(x) > 1:
raise Exception
else:
testVar = x[0]
except IndexError as e:
print(e)
print("list does not have any elements.")
except Exception as e:
print(e)
print("There are too many elements in the list.")
Here is a better way to write that.
def func(x):
if not x:
print("list does not have any elements.")
return None
if len(x) > 1:
print("There are too many elements in the list.")
return None
return x[0]
Note that if we omit the first three lines, then Python will automatically raise an IndexError when you refer to x[0].
I am having trouble understanding the following control flow.
try:
# normal execution block
except A:
# handle exception A
except B:
# handle exception B
except:
# handle other exceptions
else:
# if no exceptions, go here
finally:
# always do this
I don't understand the purpose of the a else in this context. I am coming from Java where there is no else clause for handling exceptions.
If I have something to write in the else part, I would assume that I can directly write it outside of the exception handling part either.
So, whats the necessity of the else clause in Python exception handling?
If I have something to write in else clause,I can directly write outside of the exception handle part either.
No.
def with_else(x):
try:
int(x)
except ValueError:
print('that did not work')
else:
print('that worked!')
def without_else(x):
try:
int(x)
except ValueError:
print('that did not work')
print('that worked!')
Demo:
>>> with_else(1)
that worked!
>>> without_else(1)
that worked!
>>> with_else('foo')
that did not work
>>> without_else('foo')
that did not work
that worked!
processing = True
try:
x = might_raise_a_key_error()
# a
except KeyError:
...
else:
# b
finally:
processing = False
# c
If you have a piece of code which 1) depends on x, 2) you don’t want handled by except KeyError, but 3) you do want covered by the finally clause, do you put it in # a, # b or # c?
Answer: # b.
Anyone understand how to handle an error inside of a map()? I would like to be able to handle this kind of error without the program crashing.
def add_one(val):
raise Exception('My error!')
return val+1
values = [1,2,3,4]
# Does not work
try:
new_values = map(add_one, values)
except:
new_values = []
print(list(new_values)) # Raises an Exception: My error!
# Works
try:
new_values = []
for x in values:
new_values.append(add_one(x))
except:
new_values = []
print(new_values) # Returns []
map is lazy - it doesn't actually consume the data until necessary.
So the two examples you've provided aren't equivalent.
I have built a max heap and trying to extract max as long as there are elements. If there isn't I'm returning an IndexError. This the code I'm trying to execute:
while True:
try:
print hp.extract_max()
except:
break
and in the extract_max() method:
def extract_max(self):
if self.size == 0:
return IndexError
item = self.items[0]
self.items[0] = self.items[self.size - 1]
self.heapify_down()
del self.items[len(self.items) - 1]
return item
However, the code is not breaking upon encountering an IndexError, rather printing it too. The while loop is not breaking.
<type 'exceptions.IndexError'>
<type 'exceptions.IndexError'>
....
it keeps printing the exception, without breaking the loop.
What's the problem?
As the other answer stated, you should raise the exception instead of return so:
if self.size == 0:
raise IndexError
I just want to add that you are catching all type of exceptions with except, you might want to change it to catch IndexError only to avoid catching other exceptions (ex: KeyboardInterrupt) as the following:
while True:
try:
print hp.extract_max()
except IndexError:
break
You should be raising an exception, not returning it. Do raise IndexError.
I need to keep catching an exception while indexing a list throws a IndexError exception, for example:
l = []
while((l[3]) throws IndexError):
//Add more data to the list
l += [3]
How can I keep checking to see if the method call has thrown an exception without having nested a nested try/catch block?
It depends what you would like to extend your list with. Assuming 'None' you could do it like this:
l = []
while True:
try:
l[3] = 'item'
break
except IndexError:
l.extend([None])
print l # [None, None, None, 'item']