I have to define an attribute in a class and I would like to manage error in the most pythonic way.
Here is the code I have tried so far. I can't figure out why I can not "reach" the exception in the following code.
# global variable to be used in the example
my_dict = {"key1": {"property": 10}, "key2": {}}
class Test(object):
#property
def my_attribute(self):
try:
return self._my_attribute
except AttributeError:
self._my_attribute = {}
for key, value in my_dict.items():
print(key)
self._my_attribute[key] = value['property']
except Exception:
print('error')
# I would like to manage my error here with a log or something
print("I am not reaching here")
finally:
return self._my_attribute
if __name__ == '__main__':
Test().my_attribute
I expected to reach the Exception case in the second iteration of the for loop since it is a KeyError ("key2" has no "property"). But it just passes by it. In this example, if the script is run, it does not print "I am not reaching here". Could anyone explain why I am seeing this wrong? Thanks!
The potential KeyError in self._my_attribute[key] = value['property'] is not covered by the except Exception block. Once it is raised the finally block is executed (as a matter of fact the finally block is always executed, regardless of an exception being raised or even handled). This can be easily verified by using a step-by-step debugger or with a simple print('finally') inside the finally block.
This is (among other reasons) why try blocks should be as minimal as possible. If you know that line might raise a KeyError then explicitly try-except it:
for key, value in my_dict.items():
print(key)
try:
self._my_attribute[key] = value['property']
except KeyError as e:
print('Key ', e, 'does not exist')
Related
I have below code, which I want to write in a way so that it catches proper exception when none is passed when argument value is required.
def MyFunction(MyArg1, MyArg2):
if not MyArg2:
raise ?Error?
I think it will be type error but I need the exception to be more explicit
Maybe try this
if key is None:
raise TypeError
or
if key is None:
print("There is no key.")
This is what I have trieD
if MyArg2 is None:
raise TypeError
I have below code block:
try:
if str(symbol.args[0]) != str(expr.args[0]):
print('true')
raise SyntaxError('====error')
except:
pass
Here I am trying to raise Syntax error if certain condition is true.I am testing this code block, I can see 'true' is getting printed which means condition is met but even after that also the code is not throwing syntax error.
I am trying to understand what is wrong in the above code.
You're putting pass in the except: block which is swallowing the exception. Either remove the code from the try-except block or change pass to raise
Above answer is pointing the issue, I just want to give some examples to help you better understand how try/except works:
# Just raise an exception (no try/except is needed)
if 1 != 2:
raise ValueError("Values do not match")
# Catch an exception and handle it
a = "1"
b = 2
try:
a += b
except TypeError:
print("Cannot add an int to a str")
# Catch an exception, do something about it and re-raise it
a = "1"
b = 2
try:
a += b
except TypeError:
print("Got to add an int to a str. I'm re-raising the exception")
raise
try/except can also be followed by else and finally, you can check more about these here: try-except-else-finally
let's say that i have a bunch of instruction which might all raise exceptions and I'd like to simply ignore those that fail.
failable_1
failable_2
...
failable_n
Ignoring them with the usual exception pattern might quickly become cumbersome:
try:
failable_1
except SomeError:
pass
try:
failable_2
except SomeError:
pass
...
try:
failable_n
except SomeError:
pass
This is especially true if it is about declaring a list of possibly non existing symbols:
my_list=[optional_1, optional_2, ..., optional_n]
(Let's axiomatically assume that somewhere else in the code, there was something like:
for (var,val) in zip(optional_variable_names_list, values):
exec(var+"="+repr(val))
)...
Because in this case, you cannot even write the name in the code.
my_list=[]
for variable in [optional_1, optional_2, ..., optional_n]: # problem remains here
try:
my_list.append(variable)
except:
pass
wouldn't work. You have to use eval():
my_list=[]
for variable in ["optional_1", "optional_2", ..., "optional_n"]:
try:
my_list.append(eval(variable))
except:
pass
So my question is :
Isn't there a way to write something like the on error next or on error ignore that existed in some old time languages. some kind of :
ignore SomeError:
failable_1
failable_2
...
failable_n
or
ignore NameError:
my_list=[optional_1, optional_2, ..., optional_n]
And if not, why would it be a bad idea ?
You can simplify the pattern somewhat by using a context manager that suppresses an exception by returning True if the exception that occurs is one the those specified with the constructor, or otherwise re-raises the exception:
class Ignore:
def __init__(self, *ignored_exceptions):
self.ignored_exceptions = ignored_exceptions
def __enter__(self):
return self
def __exit__(self, exc_type, exc_value, traceback):
if isinstance(exc_value, self.ignored_exceptions):
return True
raise
so that:
with Ignore(NameError, ValueError):
a = b
outputs nothing, while:
with Ignore(NameError, ValueError):
1 / 0
raises ZeroDivisionError: division by zero as expected.
I want to define a custom Exception class for the NoneType error in python inheriting from Exception class. I expect the code below to do such a thing for me but no success. Is there any way to do this?
class NoneTypeException(Exception):
pass
try:
image = cv2.imread("/path/")
gray = cv2.cvtColor(image.copy(), cv2.COLOR_BGR2GRAY) #exception should be raised here
...
except NoneTypeException:
raise NoneTypeException("Image not found") # and should be caught here
I want to the try except block raise the NoneTypeException. Any way?
While you can declare an exception to represent whatever you want, existing code won't raise it for you. In specific, operations on None already raise some well-defined errors and you cannot replace them. Strictly speaking, you cannot get the desired behaviour.
If you know that a certain section of code is vulnerable to None values, you can catch the generic Exception and raise a specific one. This hinges on the assumption that None is the only bogus value you might get:
class NoneTypeException(Exception):
pass
try:
image = cv2.imread("/path/")
gray = cv2.cvtColor(image.copy(), cv2.COLOR_BGR2GRAY)
...
except AttributeError as err: # handle generic exception from action on ``None``
raise NoneTypeException("Image not found")
Take note that this is rarely what you should be doing - the None value is a symptom, not the cause of the error. It would be more appropriate to raise a FileNotFoundError.
Since None can trigger errors anywhere, it is easier to protect against it at its origin. Checking for identity with None is very cheap:
try:
image = cv2.imread("/path/")
if image is None: # verify value immediately
raise NoneTypeException()
# safely work with image
gray = cv2.cvtColor(image.copy(), cv2.COLOR_BGR2GRAY)
...
except NoneTypeException:
raise FileNotFoundError('image not found')
I want to loop through a certain line of code until any exception or keyboard interruption occurs. But I can not reach the exception block whenever any exception occurs or due to keyboard interruption.
How can I modify my code so that I could actually reach in case of exception being thrown?
def run():
lidar = RPLidar(PORT_NAME)
iterator = lidar.iter_scans(50000)
time.sleep(2)
environment(iterator)
while True:
try:
print('Hi')
update_line(iterator)
except Exception or KeyboardInterrupt:
print("exception occur. Run again")
#lidar = RPLidar(PORT_NAME)
lidar.stop_motor()
lidar.stop()
lidar.disconnect()
break
if __name__ == '__main__':
run()
I'm surprised that code actually runs. When you say except Exception or KeyboardInterrupt you are saying only take the first thing here that evaluates to True. Since bool(Exception) is True you are only going to catch Exceptions. To catch multiple types of exceptions you would write it like this:
try:
except (Exception, KeyboardInterrupt):
It might not be triggering or non-keyboard exceptions because the exception you are trying to catch derives from BaseException and not Exception. To fix that change Exception to BaseException.
def run():
while True:
try:
print('Hi')
function_doesnt_exist(iterator)
except Exception or KeyboardInterrupt:
print("exception occur. Run again")
break
if __name__ == '__main__':
run()
When I intentionally call function that doesn't exist in your while loop it calls exception : exception occur. Run again
Perhaps you didn't generate an error properly therefore no exception is called
Also , Exception or KeyboardInterrupt means Exception since Exception includes KeyboardInterrupt and u handle them in same manner
so If you just want to catch Keyboard Interrupt then go for:
except KeyboardInterrupt:
pass
Or if you want to handle general exception and Keyboard one different do something like this:
except KeyboardInterrupt:
print("don't press ctrl+C")
pass
except:
print("exception occured")
pass