Python Try and Except - python

So recently, I learned something new which is Try and Except, and I still can't really get how it functions. Here is simple code of block. I would like some explanation on how this codes will run. Dish here refers to an item from dictionary. Note : Either ValueError or KeyError can be raised.
try:
return dish["name"].index(cost["$"])
except KeyError:
return None

let's assume you have two dictionaries:
dish = {"name": ["A", "B", "C", "D"]}
cost = {"$": "A"} # It should be any value in A,B,C,D else it will raise Value Error for dish["name"].index(cost["$"])
Now if you want to raise ValueError Then you should search the index of value that does not exist in the list in your case
if I try to do this:
# return dish["name"].index(cost["$"]) $ This will raise ValueError if
# cost['$']= "E" because "E" does not exist in dish["name"] list so it will raise value error
Let me know if it explains your use case.

Quick example but see https://docs.python.org/3/tutorial/errors.html for more info.
Your code will "try" and run the line
return dish["name"].index(cost["$"])
and if there is a ValueError then it will execute the code
return None
A ValueError is a mathematical error such as division by zero. If your code encounters a ValueError, it will run Return None, which does nothing. Try replacing return None with something like print("Exception") and force a value error to see what will happen.

Related

How to use raise ValueError?

I want to see ValueError 4 times but it is showing once, why the program cutting to search the other double numbers?
def isitDoubleorSingle(value):
if(value%2!=0):
raise ValueError("Number isn't double")
print(value)
list=[10,22,79,43,11,80]
for x in list:
isitDoubleorSingle(x)
This will solve your problem. You have to catch your Error in the except block or your script will stop running at your first raise ValueError()
edit: As #Nin17 said, you shouldn't redefine the built-in list, so renaming the list in my_list(or any name you want) should be better.
def isitDoubleorSingle(value):
try:
if(value%2!=0):
raise ValueError()
except ValueError:
print(f"Number {value} isn't double")
my_list=[10,22,79,43,11,80]
for x in my_list:
isitDoubleorSingle(x)
When you raise an exception, the program is already closed automatically, so it is not possible to display the ValueError more than once

How to / is that possible to turn off short-circuit evaluation?

I am coding a kind of command line user interface where an arbitrary boolean expression can be given as input. This expression must be repeatedly evaluated on a dictionary that is changing after some update.
Here is the simplified code :
import traceback
def update_my_dict():
return {'a': 1}
my_dict = {'a': 0}
bool_exp = input()
# -- verify code can be executed in the current context
try:
result = eval(bool_exp, my_dict)
except Exception:
print(f'Expression cannot be evaluated, evaluation raise the following error:')
print(traceback.format_exc())
quit()
# -- verify code return a boolean
if not isinstance(result, bool):
print(f'Expression return {type(result)}, expect bool')
quit()
# -- go
while not eval(bool_exp, my_dict):
my_dict = update_my_dict()
Before running the last while loop I want to verify that the expression can be executed in the current context and ensuring that its return a boolean.
My problem is if the expression is, for example bool_exp = a == 1 and b == 2 the first test evaluation of the expression while return false but do not raise exception because off lazy evaluation. But when my_dict is updated then an error will be raised.
So is that possible to, some how, disable the lazy/short-circuit evaluation for the first test evaluation ? I searched some solution using ast, but it seems complicated since bool_exp can be arbitrary long and complex, like containing entangled boolean expressions and so on.
PS: I know eval() is unsafe in a general context but my code will not be usable externaly
PS2: I know its possible to catch the exception in the while loop but it looks a bit sub-optimized knowing my_dict keys will never change when updated, only their values. Also this question is more like if its possible to control the evaluation behavior
EDIT
"but you could use & and | instead of and and or !"
No. I cannot tell what will be entered as input. So the user can input whatever s.he want.
A Correct input expression:
Should return a boolean.
Should only involve dictionary keys in the tests.
"Correct" meaning it will be repeatedly evaluated in the ending while loop without raised any exception.
We assume that the keys in the dictionary will stay constant. i.e only the values of the dict will change during the update phase. In other words, the first try/except aim to verify that the expression is only doing some test on variables that are in my_dict.
I cannot explain further the global use of this or I'll need a very long post with lost of what seems irrelevant information to resolve the issue.
You could put the "verification" code inside the loop. This makes sense as your input is changing so you should verify it on each change. You already evaluate the expression every time the dict values change, so the only added logic compared to your current code is that the isinstance check is now done as well with every change of the dict:
import traceback
def update_my_dict():
return {'a': 1}
my_dict = {'a': 0}
bool_exp = input()
# -- go
while True:
# -- verify code can be executed in the current context
try:
result = eval(bool_exp, my_dict)
except Exception:
print(f'Expression cannot be evaluated, evaluation raise the following error:')
print(traceback.format_exc())
quit()
# -- verify code return a boolean
if not isinstance(result, bool):
print(f'Expression return {type(result)}, expect bool')
quit()
if result:
break
my_dict = update_my_dict()
On the same example input a == 1 and b == 2 this will output:
Expression cannot be evaluated, evaluation raise the following error:
Traceback (most recent call last):
File "main.py", line 14, in <module>
result = eval(bool_exp, my_dict)
File "<string>", line 1, in <module>
NameError: name 'b' is not defined

Try/except if an element of a list exists

The problem
I have the following list in Python 3.6
Piko = {}
Piko['Name']='Luke'
I am trying to write a function that give the value of the element if it exist and is set and give None otherwise.
For example:
INPUT: isset(Piko['Name']) OUTPUT: Luke
INPUT: isset(Piko['Surname']) OUTPUT: None
What I have tried
1st try; based on my know how:
def isset1(x):
try:
x
except KeyError:
print(None)
else:
print(x)
2nd try; based on this answer:
def isset2(x):
try:
t=x
except IndexError:
print(None)
3rd try; based on this answer:
def isset3(x):
try:
x
except Exception:
print(None)
else:
print(x)
Any one of the previous gives me KeyError: 'Surname' error and does not output None as I wanted. Can anybody help me explaining how could I manage correctly the KeyError?
Piko.get('Surname')
Piko.get('Surname', None)
are identical and return None since "Surname" is not in your dictionary.
For future reference you can quickly discover this from the Python shell (eg ipython) by typing:
In[4]: help(Piku.get)
Which produces:
Help on built-in function get:
get(...)
D.get(k[,d]) -> D[k] if k in D, else d. d defaults to None.
The exception is happening before it even gets into your isset function. When you do this:
isset(Piko['Name'])
… it's basically the same as doing this:
_tmp = Piko['Name']
isset(_tmp)
No matter what code you put inside isset, it's not going to help, because that function never gets called. The only place you can put the exception handling is one level up, in the function that calls isset.
Or, alternatively, you can not try to lookup dict[key] to pass into isset, and pass the dict and the key as separate parameters:
def isset(d, key):
try:
print(d[key])
except KeyError:
print(None)
But at this point, you're just duplicating dict.get in a clumsier way. You can do this:
def isset(d, key):
print(d.get(key, None))
… or just scrap isset and do this:
print(Piko.get('Name', None))
Or, since None is the default if you don't specify anything:
print(Piko.get('Name'))

I want to return KeyError not None

I want to return KeyError but instead it returns None. I do not understand why.
if index == self.length or self.slots[index]==None:
raise KeyError
You don't raise a KeyError because you don't enter the if-branch. And you don't enter the if-branch because none of your conditions is true.
You probably need to adjust your condition if the test-case (that you haven't shown!) should really raise the KeyError.
To debug this issue you can insert some print-statements:
print(index, self.length, index==self.length)
print(self.slots[index], self.slots[index]==None)
if index == self.length or self.slots[index]==None:
raise KeyError
or use a debugger of your choice.
However some comments:
Normally you want to check if the index is >= to the length (that includes ==!).
You should compare to None using is. None and NotImplemented are guaranteed singletons.
Use an Exception message in KeyError, for example raise KeyError('index out of bounds or item is None! Try again.')
Functions that don't have hit an explicit return will return None. That's probably why your code returned None instead!

python try: except: pass; on multi line try statements

I have a block of statements in a try: except KeyError: pass block and wanted to know how I could have Python attempt to execute the code after the line that throws the exception.
For e.g
try:
print "entering try block"
print this_var_does_not_exists
print "past exception"
except:
pass
I want to try and print "past exception".
When I run the above code it only prints 'entering try block'
Python doesn't allow you to re-enter a failed block. Instead, you can make a nested try block:
try:
print "before"
try:
print d['not-exist']
except KeyError:
pass
print "after"
except OtherError:
print "OtherError"
Note that you can often avoid KeyErrors using .get:
try:
x = d['key']
except KeyError:
x = 0
is equivalent to
x = d.get('key', 0)
In general, try to make your try blocks as short as logically possible, so you have a better chance of dealing with the errors in an appropriate, localized fashion.
You can also use 'else' to a try/except block:
d={'a':1, 'b':2, 'd':4}
for k in 'abcd':
try:
print k, d[k],
except KeyError:
print '{} not there'.format(k)
else:
print 'I did it! Found {}'.format(k)
Prints:
a 1 I did it! Found a
b 2 I did it! Found b
c c not there
d 4 I did it! Found d
In general, the full try/except/else/final set go like this:
try:
potential_error()
except ExceptionType:
handle_that_error_somehow()
else: # 'else' to the except is SUCCESS
# There was no error
# handle success!
handle_success()
finally:
# success or failure -- do this
regardless_something_we_always_need_to_do()
python supports finally blocks, which will be executed even if there is an exception in the try block:
try:
print "entering try block"
print this_var_does_not_exists
except:
pass
finally:
print "past exception"
You can't do it with that structure. You'd need to move the extra print out of the try block. The way a try/except block works is that if an exception is raised it jumps to the appropriate except block. There's no way to go back. If you want to continue, you need to put your code either in the except or a finally, or after the whole block. Here's one example:
try:
print "entering try block"
print this_var_does_not_exists
finally:
print "past exception"
Also, don't form the dangerous habit of using bare except: clauses, especially with pass as their only content. You should catch the kinds of exceptions you can handle, and then handle them, not blindly silence all exceptions.
print with literal string will not raise exception. Put try-except only in the second print statement.
print "entering try block"
try:
print this_var_does_not_exists
except:
pass
print "past exception"
Simply put it after the try-except block
I can imagine a situation, when indeed it may be useful to execute many such one-line try-excepts without a need to add try-except block each time.
Let's say that you have a dictionary d and an object o. Object has three attributes: 'a', 'b' and 'c'. Dictionary d is generated using some function generate_dict() and may have the following keys: 'x', 'y' and 'z', but you cannot be sure which of them are present in a given dictionary. You want to assign value of key 'x' to attribute 'a', 'y' to attribute 'b' etc. In such case, you have to surround each assignment with try-catch, like this:
o = Object()
d = generate_dict()
try:
o.a = d['x']
except:
pass
try:
o.b = d['y']
except:
pass
etc. You may also replace try-excepts with checking if a given key exists in the dictionary, but the problem is still there. What happens, if you have dozens of key-attribute mappings? The number of lines grows quickly.
Another way to code this is to generate two tables of attribute and key names and execute the code in a loop using exec function, like this:
o = Object()
d = generate_dict()
attributeNames = ['a', 'b', 'c']
dataDictKeys = ['x', 'y', 'z']
for (attr, key) in zip(attributeNames, dataDictKeys):
try:
exec("o.{attr} = d['{key}']".format(attr = attr, key = key))
except:
pass
While this is not a good coding practice to do such things, still this somehow may solve your problem. But use it with caution.

Categories