Best way to check if condition or exception is thrown - python

Right now I have a function that excepts a string and is supposed to return none if the user either:
doesn't pass in a string OR
a specific exception is thrown when performing an operation on the argument
Here is how I am doing this:
def fnctn(num_str):
if not isinstance(num_str, str):
return None
try:
num = phonenumbers.parse(num_str, 'US')
except phonenumbers.phonenumberutil.NumberParseException:
return None
...
I am just wondering if there is a cleaner way of doing this. Like if I could check if the argument that was passed in was a string and check to see if the operation throws an exception or not on the same line?

This is probably the most reasonable way to do this in Python, I think. The downside of trying operations and then catching exceptions on objects which don't have well-defined behaviors is that they could be modified by the function you call. Checking whether it's a known type, i.e. str, as you do here, and if it is, then trying the operation keeps the kinds of weird behaviors to a minimum while still returning a valid result or an error (None in this case).

Related

How do I avoid except returning an empty object class

I want to include an except inside a class, but when I run the code, the except is returning an empty class object. How can I make the except return only the error message and nothing else?
class InputError(Exception):
"""Raised when input format not allowed"""
pass
class ReadMap1:
def __init__(self, input):
try:
if (type(input) == str) | (type(input) == int):
if type(input) == str:
self.input = input
else:
self.input = str(input)
else:
raise InputError
except InputError:
print("----Input not allowed----")
Output:
ReadMap1([1])
----Input not allowed----
<__main__.ReadMap1 object at 0x0000024B30B49FD0>
Many people confuse Python's __init__ with constructors from other languages, because like a constructor, __init__ is often used to initialize attributes. However, __init__ is not a constructor, but an initializer. The distinction is subtle though not terribly complicated in practice: The constructor constructs and returns an object, hence you can do my_obj = ClassConstructor() whereas the initializer only works on the object that the constructor already created. This is why Python's MyClass.__init__ returns nothing.
Your code is behaving as expected. You have told it:
if input is a string or integer, then do some stuff
if input is another type, then crash with InputError
if the above ever crashes with InputError, print an error message instead of crashing and move on
Then you pass the initializer [1] which is a Python list. This being neither a string nor a number, the interpreter raises an InputError. Normally exceptions cause a crash, but since you have the try catch, the crash is then negated, and instead a message is printed.
You can "fix" this trivially by changing your except clause to be like:
except InputError:
print("----Input not allowed----")
self.input = "default value"
It sounds like you want the initialization to be aborted in this case. Then you should remove the try-except, and let __init__ crash. The caller will then have to create the object like so:
try:
rm = ReadMap1([1])
except InputError:
print("----Input not allowed----")
Or you could omit the try-except here as well and allow the entire program to crash. It all depends: If input was invalid, could you program a way for your program to keep ticking, or is everything lost regardless?
There some additional issues in your code:
input is the name of a builtin function -- it's better to avoid shadowing it. Find a more unique name for your argument.
If you are going to check types in your if, you don't need try. You would either try to use the value and handle except TypeError, or you would use if type(..., not both.
It makes little sense to raise an exception inside a try that catches it. try is useful when the exception may arise form somewhere deep inside the code you are calling, and it would be impractical to directly check for the problem. In this case it is evident that you can check the type yourself, instead of relying on exceptions, so just do that.
If you are merely converting the value to a string, you don't need to check the type at all. Just do self.input = str(input). If it's already a string, Python will pass it unaltered. Everything else will be converted to a string (by calling the object's [or its parents'] .__str__ method).
You can define __new__() in order to intercept the creation of the object. You can return None here given a certain condition. Doing that will prevent __init__() from being called.
class ReadMap:
def __new__(cls, input):
if (type(input) == str) | (type(input) == int):
return super().__new__(cls)
print("----Input not allowed----")
return None
def __init__(self, input):
self.input = input
o = ReadMap(1)
o.input
# 1
p = ReadMap([1])
# prints ----Input not allowed----
print(p)
# None
I suspect this isn't a great idea, but I don't know how you are using this. It's pretty unexpected for the caller to call ReadMap() and get None, but it is possible. In general, I would opt for raising and letting the caller deal with the bad input — they after all sent the bad input.

Nested Try/Except or If/Else - How to tell which to use?

I realize that there have already been discussions on whether to use If/Else or Try/Except blocks. Such a question is located here: Better to 'try' something and catch the exception or test if its possible first to avoid an exception?
But I'd like to expand the discussion a little further to nested try/except and nested if/elif/else logic blocks. Here's the set up... I want to write a function that will allow users to provide either a string literal, an integer, or an iterable. This is a high level function that will provide some level of abstraction to other functions I have written. My code is like so:
def high_level_func(parameter = None):
"""
:param parameter: Can accept the string 'All', a single integer, or an iterable such
as a range or a list or tuple of ints.
"""
try:
if parameter.lower() == 'all'
# .lower because str input should be case-insensitive
return str_all_function(parameter) # Only accepts the
# string 'all' - case insensitive
except AttributeError:
# if parameter is an int or iter end up here because those types
# don't have .lower() methods
try:
for para in parameter:
try:
print(int_input_function(parameter))
except MyException:
raise MyException('An iter of something other than ints was '
'provided and cause this error.')
except TypeError:
# parameter must be an int because ints aren't iterable and end up here
return int_input_function(parameter)
In this case let's assume that I have no idea what type of input most users will prefer (i.e. it is equally likely that any given user will pass either an int, an iter, or the string 'all'. But we can safely assume that the user will most likely never pass a list of strings or tuple of strings -illegal iters)
Is this ok to do or would I be better off checking the type of the input and doing an if/elif/else (IEE) code block? Would an IEE code block be significantly easier to read in your opinion?
Alternative suggestion: what about using a combination of try/except and IEE? The try/except might try to lower the input if it is the string literal 'all', for example, and the IEE would be nested in the except block to check the alternative cases (integer or iter or illegal type)
And in more general, how can I tell which method is the fastest without writing the function three different times and testing each one?
An even further question is, if the Try/Except is faster on average than an If/Elif/Else test, but we think If/Elif/Else has better readability, how much faster should the Try/Except method be to warrant throwing readability out the window or does readability always prevail in the face of speed? Or is this up to the coder's/team's discretion?
I think your input functions should be responsible for validating the input, not the function that calls them. After that, you can let the high level function remain high level and keep trying to use one of them until it succeeds:
def high_level_function(parameter=None):
try:
return str_input_function(parameter)
except ValueError: # Raised by str_input_function on bad input.
pass
try:
return iter_input_function(parameter) # MyException now propagates itself.
except ValueError: # Raised by iter_input_function on bad input.
pass
try:
return int_input_function(parameter)
except ValueError: # Raised by int_input_function on bad input.
pass
# This should never be hit:
raise ValueError("parameter has unsupported type: " + type(parameter).__name__)

python3 ValueError value

I am trying to write a function using python3, with exception handling.
I thought ValueError is the right tool to check if the value is in given range, as given here in python3 doc which says:
function receives an argument that has the right type but an inappropriate value
So, in this my tiny snippet, I am expecting to use ValueError to check range(0-1) which is not doing:
while True:
try:
imode = int(input("Generate for EOS(0) or S2(1)"))
except (ValueError):
print("Mode not recognised! Retry")
continue
else:
break
print(imode)
which yeilds:
Generate for EOS(0) or S2(1)3
3
Sure, I can do the value checking as:
if (imode < 0 or imode > 1):
print("Mode not recogised. RETRY!")
continue
else:
break
but the ValueError seems do do this thing.
There are several question on ValueError here, but none of them checking "inappropriate value, e.g. this
I am a novice and python is not my main language.
Kindly give me some insight.
I think you misunderstand what ValueError (and in general, an Exception) is.
Exceptions are a way for a method to signal to its caller that some critical error condition has been encountered that would prevent that method from executing as intended. Python's try-except-finally control structure provides a way for the caller to detect those error conditions and react accordingly.
ValueError is a standard Exception raised by various methods that perform range-checking of some kind to signal that a value provided to the method fell outside the valid range. In other words, it's a universal way of signaling that error condition. ValueError by itself doesn't do any kind of checking. There are many other standard Exceptions like this; KeyError signifies that you tried to access a key in a mapping structure (like a dict or set) that didn't exist, IndexError means you tried to index into a list-like structure to an invalid location, etc. None of them actually do anything special in and of themselves, they're simply a way of directly specifying exactly what kind of problem was encountered by the called method.
Exceptions go hand in hand with the idiom in python that it is generally considered 'easier to ask forgiveness than permission'. Many languages support exceptions of course, but Python is one of the few where you will very frequently see code where the Exception case is actually a commonly-followed code path rather than one that only happens when something has gone really wrong.
Here is an example of the correct use of a ValueError:
def gen(selection):
if imode == 0:
# do EOS stuff here
elif imode == 1:
# do S2 stuff here
else:
raise ValueError("Please Select An Option Between 0-1")
def selector():
while True:
try:
gen(int(input("Generate for EOS(0) or S2(1)")))
break
except ValueError as e: # This will actually satisfy two cases; If the user entered not a number, in which case int() raises, or if they entered a number out of bounds, in which chase gen() raises.
print(e)
Note there are probably much more direct ways to do what you want, but this is just serving as an example of how to correctly use a ValueError.

What exception to raise for python function arguments

I'm creating a function right now that takes in two lists. I want these two lists to be of equal size. I'm trying to figure out what kind of exception I should throw (or If I should throw an exception at all) if they aren't the same size. I kind of want to say ValueError but this is a check that doesn't actually pertain to any single value.
For clarities sake, here's my function stub.
def create_form(field_types, field_discriptions):
pass
I would just use assert and raise an AssertionError:
assert len(field_types) == len(field_descriptions), "Helpful message"
Otherwise, ValueError with a message seems like the best choice.
You can create your own subclass of exception called ArraysNotEqualSizeException. Might be a bit overkill, but it gets the point across.
throw an exception as the first thing in the function. A function-critical error should not do anything without making sure it can do what it wants or it could have bad effects
This isn't a giant error; you should use an assert
Places to consider putting assertions:
checking parameter types, classes, or values
checking data structure invariants
checking "can't happen" situations (duplicates in a list, contradictory state variables.)
after calling a function, to make sure that its return is reasonable
-Python wiki
assert len(listone) == len(listtwo),
"the function cannot continue because\
the two arguments passed are of invalid length"
a ValueError as suggested by Blender would be the right type if you want to use a generic exception, however that's usually reserved for larger issues and would be less helpful.
for quick reference:
"ValueError
Raised when a built-in operation or function receives an argument that
has the right type but an inappropriate value, and the situation is
not described by a more precise exception such as IndexError." -Python docs

Python: performing a function to check if the file has a suffix

I wrote this function to use from an other function, checking if the output has the correct suffix. Before I use it I have two questions:
Is TypeError the best exception to use in this case?
Is there some built-in function I could use instead of mine?
Code:
def suffix_NameCheck(inFile):
if os.path.splitext(inFile)[1] is None:
raise TypeError('"%s" has not a suffix' % inFile)
else:
return inFile
There is not a built-in function that does this, because
Not all file systems really use extensions.
It's probably more common to just use the if statement on its own, rather than throwing it in a function.
The reason is that you're probably going to have to catch that exception somewhere (unless you intentionally want it to end the program, in which case, there's probably a better way to do it than throwing an exception, e.g. sys.exit). The code to catch the exception would be at least as involved as the code to just do the if check itself and handle it.
I would not raise an exception from a function named suffix_NameCheck, but rather return True or False instead. The normal operation of suffix_NameCheck is not affected by wether or not there is a correct suffix on the value, it's job is to check for that suffix.
The function that uses suffix_NameCheck could still raise an exception; ValueError may be a better exception to use in that case.
I think this is more appropriately a ValueError. The problem you are attempting to report is that the user provided a file path/name argument as a string that has no file extension. That's a problem with the value of the string, not anything's type.
Other answerers have a point that this sort of functionality at first glance should really be returning a bool, but given that that use case is covered simply with bool(os.path.splitext(candidate)[1]), I think that if you really do want to raise an exception here, you are already working with a lower level function that returns a bool.

Categories