What if an if-statement is equal to error? - python

In checking for amicable numbers I've made the following if-statement (dict is dictionary):
if n == dict[lib[n]]:
amic[n] = dict[n]
But if the n value is not in the dictionary it returns an error; as it should. But I'd like it to continue because an error means "it's not equal" and it should continue to the next n.
Is this possible?

You probably want dict.get() which returns None (or another default of your choosing). For example n == lib.get(lib.get(n))

You could wrap in a try block, and ignore the exception, but given a bit more context, there's probably a better way... (lib[lib[n]] just looks odd...)
This will catch an IndexError for both lib and amic though...
try:
if n == lib[lib[n]]:
amic[n] = lib[n]
except IndexError as e: # or KeyError if a dict
pass

Related

Using try-excepts in nested for loops

I have a nested loop where I perform a calculation over every grid-point in a 3-dimensional array. Some of these grid-points trigger an error. I want to calculate every possible grid-point and skip those that trigger the error.
I've tried:
with sharedmem.MapReduce(np=45) as pool:
def calc_func(abc):
for k in range(241):
try:
for j in range(int(datetime_range)):
for l in range((abc), abc+1):
value = calc(pr[j,k,l], te[j,k,l], de[j,k,l])
array[j,k,l] = value
except (IndexError, ValueError):
continue
pool.map(cape_func, range(0, 479))
^ Above, some grid-points are calculated, but I think when k values are caught in the exception, the code doesn't calculate the rest of the grid-points for that k.
Below, I tried adding another try-except block to iterate over all of the grid-points. I don't think this worked - it seems to be looping infinitely.
with sharedmem.MapReduce(np=45) as pool:
def calc_func(abc):
for k in range(241):
try:
for j in range(int(datetime_range)):
try:
for l in range((abc), abc+1):
value = calc(pr[j,k,l], te[j,k,l], de[j,k,l])
array[j,k,l] = value
except (IndexError, ValueError):
continue
except (IndexError, ValueError):
continue
pool.map(cape_func, range(0, 479))
I think you might be looking for a pass statement instead of a continue. But I might not have understood your questions well. On the side note, can you not vectorise it?
It also looks like the only thing that could throw Index or Value errors is the calc function, since all your loop are over a ranges. Why don't you just wrap the 2 code lines with the function and array assignment?

Python conventions with respect to if conditions

In python, is it frowned upon to use extra conditions within an if statement to avoid error, or should this be done separately from the if statement?
Example:
I want to make sure that d, which will be either a empty string or a number string is not blank and not less than 1. If d is a empty string, it can not be converted to a float. The statement is evaluated as false before trying to convert to float so I don't get an error. Is this bad practice?
def main():
d = "2.25"
check_d(d)
d = "0"
check_d(d)
d = ""
check_d(d)
this looks prettier to me
def check_d(d):
if d and float(d) >= 1:
return True
print('d must be defined with value 1 or greater')
return False
this was my first instinct
def check_d_old(d):
try:
if float(d) >= 1:
return True
except:
pass
print('d must be defined with value 1 or greater')
return False
You don't need the if d part if you include it in the try. Something like this would work, where either you'll get a ValueError if it's not a number, or it'll raise a ValueError if it is a number but under 1.
def check_d(d):
try:
if float(d) >= 1:
return 0
else:
raise ValueError()
except ValueError:
print('d must be defined with value 1 or greater')
return 1
It's fine using extra conditions, but if you can skip a few unnecessary ones, it'll run faster overall. Also, try to not just use except, find out which type of error you want to be looking for.
The first is fine assuming that d will always fit your criteria but the second example is more robust.
For example when d = "a" the condition if d and float(d) >= 1: will raise the ValueError where as the try: except will catch it and work properly.
So if your criteria of "d will be either a blank string or a number string" is absolute then the first is fine, however if d could have other values then you may want to use the second.

True and False Statements, finding variable types

Im trying to decide whether a string variable is a valid integer or float, ive tried try statements but using ASCII seems to be better. I can't get this to work, probably something with the returns and boolean.
def validation(valid):
var=input("no...")
state=True
y=0
for x in range(len(var)):
if state==False or y==2:
valid=False
return valid
if var[x] == chr(46) or chr(48) <= var[x] <= chr(57):
if var[x] == chr(46):
y+=1
state=True
else:
state=False
valid=True
valid = validation(valid)
print(valid)
The ASCII characters 46 and 48-57 are a decimal point and numbers 0-9. If there more than one decimal point (representing by y) than it also returns a false statement.
Simple and powerful approach:
def isNum(txt):
try:
float(txt)
return True
except ValueError:
return False
There is a much simpler way to do this:
try:
float(x)
except ValueError as e:
print e
print "Not a float"
else:
try:
int(x)
except ValueError as e:
print e
print "not an integer"
You can combine these into a method pretty easily.
Your code isn't very efficient, and it doesn't handle negative numbers, or floats written in scientific notation. Using try, as in fiacre's answer is the standard way to do this in Python.
But to answer your question, you don't have a return statement after the for loop, so if all your tests succeed your function returns the default value of None. So you just need to put a return True at the end of your function.
You can make your code a little more efficient by iterating over the string values and testing the characters directly rather than indexing into the string and using chr(). Eg,
for c in var:
if c == '.' or '0' <= c <= '9':
# etc
Alternatively,
valid_chars = set('-.0123456789')
for c in var:
if c in valid_chars:
# etc
FWIW, in your existing code Python has to re-calculate chr(46) etc on every loop. Sure, that's a pretty fast operation, but it's still wasteful.
Also, there's no need to have both state and valid in the function.

What's the point of the return in this code?

So, I have this function below:
def remove_all(lst):
i = 0
while i < 10:
try:
print('Removing... ')
print(int(lst.pop()) + 10)
print("Removed successfully.")
# As soon as an IndexError is raised, jump to the following block of code...
except IndexError as err:
# if you encounter an indexerror, do the following:
print("Uh oh! Problems.")
return
#As soon as a Value error is raised, jump here.
except ValueError as err:
print("Not a number")
i = i + 1
What does the return do? There is no value after the return, so does it mean None or True?
And what is the point of having the return there if the value is none?
Thanks!
The return value is None.
In this context, the function never returns a value. The point of the return is to stop execution
The return statement can be used as a kind of control flow. By putting one (or more) return statements in the middle of a function, you could exit/stop the function.
This causes the function to exit when an IndexError is encountered, just without returning any value.
In your example, there is no return value.
Given you would call the function like this:
a = remove_all(lst)
a will be None because the function simply returns nothing.
To check the success of the function, you could implement it like this:
def ....
try:
...
exception 1:
your error handling...
return False
exception 2:
your error handling...
return False
continue function...
return True
When you then check the return value of your function, you will see if it has been executed till the end (True) or if it raised an error before (False).
However, this will not continue the execution of this particular function after one of the defined errors occurred.

break and continue in function

def funcA(i):
if i%3==0:
print "Oh! No!",
print i
break
for i in range(100):
funcA(i)
print "Pass",
print i
I know script above won't work. So, how can I write if I need put a function with break or continue into a loop?
A function cannot cause a break or continue in the code from which it is called. The break/continue has to appear literally inside the loop. Your options are:
return a value from funcA and use it to decide whether to break
raise an exception in funcA and catch it in the calling code (or somewhere higher up the call chain)
write a generator that encapsulates the break logic and iterate over that instead over the range
By #3 I mean something like this:
def gen(base):
for item in base:
if item%3 == 0:
break
yield i
for i in gen(range(1, 100)):
print "Pass," i
This allows you to put the break with the condition by grouping them into a generator based on the "base" iterator (in this case a range). You then iterate over this generator instead of over the range itself and you get the breaking behavior.
Elaborating BrenBarns answer: break fortunately will not propagate. break is to break the current loop, period. If you want to propagate an event, then you should raise an exception. Although, raising the exception to break the loop is a really ugly way to break loops and a nice way to break your code.
KISS! The simplest would be to check the condition directly in the loop
def my_condition(x):
return x == 4
for i in xrange(100):
if my_condition(i): break
print i
If, for some reason, you want to propagate an exception, then you use it like this
# exception example
for i in xrange(100):
if i == 4: raise Exception("Die!")
print i
As mentioned, it is a really ugly design. Imagine you forget to catch this exception, or you change its type from Exception to MyBreakException and forget to change it somewhere in try/except higher part of the code...
The generator example has its merits, it makes your code more functional style (which I presonally adore)
# generator example
def conditional_generator(n, condition):
for i in xrange(n):
if condition(i):
break
else:
yield i
for i in conditional_generator( 100, my_condition ):
print i
...which is similar to takewhile, mentioned by eumiro
def funcA(i):
if i%3==0:
print "Oh! No!",
print i
return True
else:
return False
for i in range(100):
if funcA(i):
break
print "Pass",
print i
Break won't propagate between functions, you need to put it directly within the loop somewhere.

Categories