Python conventions with respect to if conditions - python

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.

Related

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.

Python Modulo TypeError

I wanted to create simple code to test if number is odd or even.
I am using Python 2.7.3.
def oddoreven(a):
try: int(a)
except: return "Error"
if a%2==0: return 1
else: return 0
Instead the code fails with error: TypeError: not all arguments converted during string formatting. The error points to the line beginning with if a%2==0....
While researching this problem I found examples indicating that code like this should work. For example answers to this question offer similar code as solution: python - checking odd/even numbers and changing outputs on number size
So what is wrong with my code?
It's because you first test if a can be converted to an int (which is fine), but then you ignore this test and keep going with the string you provided in argument.
Python is a dynamically typed language, but also strongly typed, which means you can change the type of a variable after it's been declared, but this change has to be explicit (more about this here).
In your case, it means you can't do if a % 2 == 0 if a is a string.
You could do this for instance:
def oddoreven(a):
try:
my_int = int(a)
except TypeError:
return "The argument provided could not be converted into an int"
if my_int % 2 == 0:
return 1
else:
return 0
the int function doesn't change the a in-place, you need to assign it to a :
>>> def oddoreven(a):
... try: a=int(a)
... except: return "Error"
... if a%2==0: return 1
... else: return 0
...
>>> oddoreven('2')
1
>>> oddoreven('5')
0
>>> oddoreven('a')
'Error'
As user2357112 stated. (int)a does not convert a to a int. so when you check its modulus you still must convert it.
def oddoreven(a):
try: int(a)
except: return "Error"
if int(a)%2==0: return 1
else: return 0
print oddoreven(32)
works fine.
As a side note, catching any exception is generally frowned upon. You may want to narrow it down like:
def oddoreven(a):
try: int(a)
except TypeError: return "Error"
if int(a)%2==0: return 1
else: return 0
print oddoreven(32)

how to change my value for int or str (vice versa)

I'm having an issue where my code gives me:
TypeError: unorderable types: str() >= int()
Thing is, I don't know how to switch my values from str to int or vice-versa :
def separate(seq):
result=[0,0];
a=0
b=0
for c in seq:
if(c=='0'):
a+=1
elif(c=='1'):
b+=1
else:
c>=2,
pass
return result
and
cursor1=mydb.cursor()
statement ="SELECT prediction FROM splicingdb.proteinsignalexperimental, splicingdb.disorderpredictions where proteinsignalexperimental.ID = disorderpredictions.ID AND source regexp 'disprot'"
cursor1.execute(statement)
resultat = cursor1.fetchall()
#print (resultat)
in [statement]: int(i)
s=statement
print(resultat)
zero, one = separate(s);
print ("zero: %d"%zero)
print ("one: %d"%one)
I'm guessing your actual separate code looks like this, once you adjust for the indentation errors:
def separate(seq):
result=[0,0];
a=0
b=0
for c in seq:
if(c=='0'):
a+=1
elif(c=='1'):
b+=1
else:
c>=2,
pass
return result
The line c>=2, is giving a TypeError because you're trying to compare the character c with the integer 1. Looks like you intended for that line to merely be a comment anyway, so just prefix it with a pound sign.
#c>=2,
Or just drop the else clause entirely.
for c in seq:
if(c=='0'):
a+=1
elif(c=='1'):
b+=1
#no else needed here!
return result
(By the way, you probably mean to do return [a,b]. Returning result will always give you [0,0] no matter what seq contains)
else: #
c>=2, #<----- Not sure what that is, but maybe you want to get rid of it!
pass #<----- I suggest to get rid of the whole "else" block.
that code compares c to an int.
the preceding if-elif are comparing c to strings:
if(c=='0'):
...
elif(c=='1'):
...
c are the elements of statement.
and
statement ="SELECT prediction FROM host.proteinsignalexperimental, host.disorderpredictions where proteinsignalexperimental.ID = disorderpredictions.ID AND source regexp 'disprot'"
c is a str that you are comparing to an int in what appears to be a syntactic error (or a very strange syntax) in following your else.
if you want to change your variable type, you could do like this:
c = int(c) #<--- changes c to int
# or
c = str(c) #<--- changes c to str
or do the comparisons without changing the type:
int(c) == 2 # <--- Choose which applies to your data.
str(c) == '2'

What if an if-statement is equal to error?

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

Using reduce mul to return 1 instead of None on blank list

I'm trying to return 1 instead of None when I pass an empty list through reduce(mul, a). My code:
from operator import mul
def product_list(a):
for b in a:
b = reduce(mul, a)
if b == None:
return 1
return b
print product_list([])
No matter where I place the if statement to catch for a blank list, I still receive None as output. I am still learning basics, but this makes no sense to me. I've even tried
from operator import mul
def product_list(a):
if a == None:
return 1
else:
for b in a:
b = reduce(mul, a)
if b == None or a == None:
return 1
return b
print product_list([])
just to see if it would catch the None and return 1. Does reduce() not act the way I think that it does, or is there an obvious mistake in my code that prohibits returning 1 and forces a return of None?
When a is an empty list, your function doesn't return anything, and the default return value is None.
Test for the empty list at the top:
if not a:
return 1
In your second function you only test for if a == None, but an empty list [] is never equal to None. Note that the idiomatic way to test for None is using the is object identity test instead:
if a is None:
By testing for not a instead, you catch both the case where a is an empty list and a being None.
Your code otherwise makes little sense. You loop over a but return and exit the function in the first iteration:
for b in a:
b = reduce(mul, a)
if b == None:
return 1
return b # exit the function here, having only looked at the first element in `a`.
However, I had to fix the indentation in your post and may have misunderstood the indentation of those return statements, in which case you would get a NameError instead when passing in an empty list.
You can pass a third value to reduce, which is used as a starter value.
In [6]: reduce(mul, [], 1)
Out[6]: 1
This is the best way to deal with an empty list. The case None should really be dealt with elsewhere, because it's a different kind of error: it's nothing wrong with the semantics of the program, it's because someone else has given you bad data. You should catch that explicitly, as e.g.
if not isinstance(..., collections.Iterable):
# do something
Of course, reduce will raise an error if you pass it something not iterable, and that may suffice for you.
Note that you're not passing an empty list to reduce as you say. Try it:
>>> reduce(operator.mul, [])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: reduce() of empty sequence with no initial value
I think that perhaps you don't understand the function reduce. We can't hold it against you though -- it's not used much in python code.
Perhaps you wanted to define a function like this:
from operator import mul
def product_list(a):
try:
return reduce(mul,a)
except TypeError:
return 1
Now you can try it:
print product_list([1,2,3,4]) #24
print product_list([]) #1
if a is None or len(a) == 0:
return 1
Check the empty list condition as above.

Categories