I would like to find a way to get the variables I assigned before an exception is made. E.G if the code is
try:
a=b
c=d
e=f
except:
bla bla
And an exception is generated at "e=f," I still want a=b and c=d
Is it possible? I realize I could make this multiple try statements but is there something I can do in one step?
Yes, it is perfectly possible. Below is a demonstration:
>>> try:
... a = 1
... b = 2
... c = 1/0 # This will raise a ZeroDivisionError
... except ZeroDivisionError:
... print 'an error occurred'
...
an error occurred
>>> a # a still exists
1
>>> b # so does b
2
>>> c # only c is undefined
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'c' is not defined
>>>
try/except is designed to execute the code in the try-block normally until an exception is raised. When that happens, the try-block is immediately exited. This means that only the code after the line that raised the exception is ignored.
The best you can do is to limit the number of expressions inside your try block.
If you need to know where the exception is raised, you are probably better off using multiple try...except's like you mentioned in your queestion, since there is no (practical) way to know where the exception was raised.
If the expressions are of the same type, you may want to put them in lists though, and loop over them, like:
vars = [a, b, c]
values = [1, 2, 0]
for i, (var, value) in enumerate(zip(vars, values)):
try:
var /= value
except ZeroDivisionError:
print 'The exception was raised on the {}. iteration'.format(i)
continue
try:
a = "foo"
c = "bar"
e = unknown_function()
except:
pass
print a, c # prints "foo bar"
Both a and c are set, you can simply use their values after the exception is handled. e is not set to anything as an exception was raised when that line was executed.
If I understand you correctly, this will happen by default. Raising an exception does not magically undo everything that has already happened inside the try block. In your example, if an error occurs on the assignment of e, a and c will still have the values they were assigned.
try:
a = b
c = d
e = f # oh noes! error! Try block skips to the end!
except: pass
print (a) #but a and c are still there
print (c)
This is a straight forward method without much of a hassle . This is the best way out when you cant predict what type of error can occur, or multiple errors can occur .
try :
a=10
except :
print "bla A"
try :
b=20
except:
print "bla B"
try:
c=d
except :
print "bla C"
Is it something like this that you want ?
import sys
code = """
b = 100
d = 200
a=b
c=d
e=10/0
g=e
h = 100
"""
for line in filter(None,code.splitlines()):
print line
try:
exec line
except:
sys.excepthook(sys.exc_info()[0],sys.exc_info()[1],None)
result
b = 100
d = 200
a=b
c=d
e=10/0
ZeroDivisionError: integer division or modulo by zero
g=e
NameError: name 'e' is not defined
h = 100
Related
If the number in the line is already wroten, I must print 0 and if it's not, I must print 1.
Got ValueError and tried to catch it, but it fails.
a=int(input())
b=input()
n='1 '
c=b.split()
for i in range(a-1):
l=c[0]
c.remove(l)
d=c.index(l)
try:
a=a
except ValueError as ve:
if d > 0:
c = c.replace(l,'zero')
else:
c=c.replace(l,'one')
for amogus in range(a):
a=a.replace('one',1)
a=a.replace('zero',0)
print(a)
The error tracebacks like so:
Traceback (most recent call last):
File "program.pys3", line 8, in <module>
d=c.index(l)
ValueError: '1' is not in list
The first part of your loop is like this:
for i in range(a-1):
l = c[0]
c.remove(l)
d = c.index(l)
l is set to the first item in the list c. You then remove that item. The last line above then tries to find the index of that item again. This will work if there is another one, but if not will throw the error you report.
Did you mean to put the last line inside the try:?
for i in range(a-1):
l = c[0]
c.remove(l)
try:
d = c.index(l)
except ValueError as ve:
if d > 0:
c = c.replace(l,'zero')
else:
c = c.replace(l,'one')
Now a friendly warning: if this fixes the reported error you will encounter another one.
In the event of an IndexError, is there a way to tell which object on a line is 'out of range'?
Consider this code:
a = [1,2,3]
b = [1,2,3]
x, y = get_values_from_somewhere()
try:
a[x] = b[y]
except IndexError as e:
....
In the event that x or y is too large and IndexError gets caught, I would like to know which of a or b is out of range (so I can perform different actions in the except block).
Clearly I could compare x and y to len(a) and len(b) respectively, but I am curious if there is another way of doing it using IndexError.
There is a way, but I wouldn't consider it as very robust. There is a subtle difference in the error messages:
a = [1,2,3]
b = [1,2,3]
a[2] = b[3]
---------------------------------------------------------------------------
IndexError Traceback (most recent call last)
<ipython-input-69-8e0d280b609d> in <module>()
2 b = [1,2,3]
3
----> 4 a[2] = b[3]
IndexError: list index out of range
But if the error is on the left hand side:
a[3] = b[2]
---------------------------------------------------------------------------
IndexError Traceback (most recent call last)
<ipython-input-68-9d66e07bc70d> in <module>()
2 b = [1,2,3]
3
----> 4 a[3] = b[2]
IndexError: list assignment index out of range
Note the 'assignment' in the message.
So, you could do something like:
a = [1,2,3]
b = [1,2,3]
try:
a[3] = b[2]
except IndexError as e:
message = e.args[0]
if 'assignment' in message:
print("Error on left hand side")
else:
print("Error on right hand side")
Output:
# Error on left hand side
Again, I wouldn't trust it too much, it would fail if the message changes in another version of Python.
I had a look at these parts of the source code, these different messages are really the only difference between the two errors.
The IndexError exception does not store information about what raised the exception. Its only data is an error message. You have to craft your code to do so.
a = [1,2,3]
b = [1,2,3]
x, y = get_values_from_somewhere()
try:
value = b[y]
except IndexError as e:
...
try:
a[x] = value
except IndexError as e:
...
I want to add I tried to recover the culprit through inspect.frame and was unable to do so. Thus I suspect there really is no robust way.
Finally, note that this is specific to IndexError as other exceptions may contain the needed information to infer what caused them. By example a KeyError contains the key that raised it.
A more robust approach would be to tap into the traceback object returned by sys.exc_info(), extract the code indicated by the file name and line number from the frame, use ast.parse to parse the line, subclass ast.NodeVisitor to find all the Subscript nodes, unparse (with astunparse) and eval the nodes with the frame's global and local variables to see which of the nodes causes exception, and print the offending expression:
import sys
import linecache
import ast
import astunparse
def find_index_error():
tb = sys.exc_info()[2]
frame = tb.tb_frame
lineno = tb.tb_lineno
filename = frame.f_code.co_filename
line = linecache.getline(filename, lineno, frame.f_globals)
class find_index_error_node(ast.NodeVisitor):
def visit_Subscript(self, node):
expr = astunparse.unparse(node).strip()
try:
eval(expr, frame.f_globals, frame.f_locals)
except IndexError:
print("%s causes IndexError" % expr)
find_index_error_node().visit(ast.parse(line.strip(), filename))
a = [1,2,3]
b = [1,2,3]
x, y = 1, 2
def f():
return 3
try:
a[f() - 1] = b[f() + y] + a[x + 1] # can you guess which of them causes IndexError?
except IndexError:
find_index_error()
This outputs:
b[(f() + y)] causes IndexError
Something like this perhaps?
a = [1,2,3]
b = [2,3,4]
x = 5
y = 1
try:
a[x] = b[y]
except IndexError:
try:
a[x]
print('b caused indexerror')
except IndexError:
print('a caused indexerror')
No, there is no way of deducing which of the two is out of bounds using the IndexError thrown.
I have a statement like this.
I just want to know which of the two assert statement has thrown the exception.
try:
assert re.search("xyz", statement)
assert re.search("abc", statement)
except AssertionError:
print "AssertionError : Expected Error message not found"
Thanks for the answer.
As mentioned in The assert statement docs, you can give an expression after the assertion test expression; that second expression will be passed in the AssertionError. Here's a simple demo:
for n in (-5, 10, 20):
try:
assert 0 <= n, '%d is too low' % n
assert n <= 10, '%d is too high' % n
print('%d is ok' % n)
except AssertionError as err:
print "AssertionError:", err
output
AssertionError: -5 is too low
10 is ok
AssertionError: 20 is too high
That second expression doesn't have to be a string, it can be anything. Since assertions should only be used to verify program logic, not to validate user data, I generally don't bother passing a nicely-formatted string, I just pass a tuple containing the relevant values, and maybe an identifying string. Eg,
assert (a * b > c), ('Bad product', a, b, c)
You could use functions from the traceback module. For example, extract_tb returns a list of tuples (named tuples in Python 3.5 and newer) representing the stack trace entries. Each tuple contains a line number as well as the source text line (if available).
import traceback
try:
assert 1
assert None
except AssertionError as e:
for x in traceback.extract_tb(e.__traceback__, limit=-1):
print(x.lineno, repr(x.line)) # Prints 5 'assert None'
You are able to print the last raised exception with traceback.print_exc(). An example:
>>> import traceback
>>> try:
... a = 1 / 0
... except:
... traceback.print_exc()
...
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
ZeroDivisionError: integer division or modulo by zero
There is also traceback.format_exc() in case you don't want to print.
Maybe you want to differ the exceptions?Then Getting exception details in Python can help you.
Copying the answer here:
import sys
try:
assert re.search("xyz", statement)
assert re.search("abc", statement)
except AssertionError:
type, value, traceback = sys.exc_info()
Then you can print out the info.
What is the easiest way to check to see if a list or dict exists in python ?
Im using the following but this isn't working:
if len(list) == 0:
print "Im not here"
Thanks,
For the lists:
if a_list:
print "I'm not here"
The same is for the dicts:
if a_dict:
print "I'm not here"
You can use a try/except block:
try:
#work with list
except NameError:
print "list isn't defined"
When you try to reference a non-existing variable the interpreter raises NameError. It's not safe, however, to rely on the existence of a variable in your code (you'd better initialize it to None or something). Sometimes I used this:
try:
mylist
print "I'm here"
except NameError:
print "I'm not here"
If you're able to name it - it obviously "exists" - I assume you mean to check that it's "non-empty"... The most pythonic method is to use if varname:. Note, this won't work on generators/iterables to check if they will return data as the result will always be True.
If you just want to use a certain index/key, then just try and use it:
try:
print someobj[5]
except (KeyError, IndexError) as e: # For dict, list|tuple
print 'could not get it'
Examples:
mylist=[1,2,3]
'mylist' in locals().keys()
Or use this:
mylist in locals().values()
Simple console test:
>>> if len(b) == 0: print "Ups!"
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'b' is not defined
>>> try:
... len(b)
... except Exception as e:
... print e
...
name 'b' is not defined
Examples show how to check if a list has elements:
alist = [1,2,3]
if alist: print "I'm here!"
Output: I'm here!
Otherwise:
alist = []
if not alist: print "Somebody here?"
Output: Somebody here?
If you need to check existence/nonexistence of a list/tuple maybe this can be of help:
from types import ListType, TupleType
a_list = [1,2,3,4]
a_tuple = (1,2,3,4)
# for an existing/nonexisting list
# "a_list" in globals() check if "a_list" is defined (not undefined :p)
if "a_list" in globals() and type(a_list) is ListType:
print "I'm a list, therefore I am an existing list! :)"
# for an existing/nonexisting tuple
if "a_tuple" in globals() and type(a_tuple) is TupleType:
print "I'm a tuple, therefore I am an existing tuple! :)"
If we need to avoid of in globals() maybe we can use this:
from types import ListType, TupleType
try:
# for an existing/nonexisting list
if type(ima_list) is ListType:
print "I'm a list, therefore I am an existing list! :)"
# for an existing/nonexisting tuple
if type(ima_tuple) is TupleType:
print "I'm a tuple, therefore I am an existing tuple! :)"
except Exception, e:
print "%s" % e
Output:
name 'ima_list' is not defined
---
name 'ima_tuple' is not defined
Bibliography:
8.15. types — Names for built-in types — Python v2.7.3 documentation https://docs.python.org/3/library/types.html
Check (1) variable exist and (2) check it is list
try:
if type(myList) is list:
print "myList is list"
else:
print "myList is not a list"
except:
print "myList not exist"
s = set([1, 2, 3, 4])
if 3 in s:
print("The number 3 is in the list.")
else:
print("The number 3 is NOT in the list.")
You can find more about it here: https://docs.quantifiedcode.com/python-anti-patterns/performance/using_key_in_list_to_check_if_key_is_contained_in_a_list.html
I can't understand why this code:
x='aaaa'
try:
self.assertTrue(x==y)
except:
print (x)
generates me this error
AssertionError: False is not True
It should be handle it by
print(x)
EDIT
original code is:
try:
self.assertTrue('aaaa'==self.compare_object_name[1])
except:
print ('aaa')
#Space_C0wb0y I can't give you full code because it is not my code, and I don't have a permission.
You should include the code that defines the assertTrue method. From the output you get, I'd say that it actually does not throw an exception, but deals with it internally (thus the error message being printed, and not your value).
You can use the built-in assert statement of Python, which works as expected:
x = 'aaaa'
y = 'bbb'
try:
assert(x == y)
except:
print (x)
Output:
>>>
aaaa