Conditionals and the nature of truth


Introduction

So, we've now spent a few action-packed sessions learning about python, and we've learned quite a bit. We've learned what variables are, how to print variables out, and how to store and manipulate more complex data in more complex data structures. However, we're still missing one of the very essential components of programming.

My goal, when I first started programming, was to make the computer do my work for me. I imagine that this is your goal, too-- instead of normalizing that microarray data or computing that crystal structure fit with a pocket calculator and a bucket of coffee, you want to be able to say 'Computer, do my work,' and then have it done. Of course, you'd have to say it a little more clearly than that-- for instance, to pick out overexpressed membrane proteins from microarray data, you could tell the computer that for each gene in the genome:

"If the gene location is 'membrane', tell me if the first column is much greater than the second column."

What's the magic word there? 'if'

Indeed, the 'if' statement is one of the most fundamental components of programming, and it is found in some form or another in every general-purpose programming language (and nearly all specialized ones, too). It simply tells the computer to execute a execute a block of code if a given statement is true. If the statement is false, the code is skipped. Although the concept is simple, conditional statements like 'if' allow you to give rudimentary intelligence to your programs.

The syntax is easy

How do we write this? In python, it's

if <something that may or may not be true>:
  1. do these things
  2. also do these things

We will discuss what makes things 'true' in a minute, but for now we should focus on the syntax. Beyond the 'if' and the colon, note that python will execute all of the code that is indented-- that's the signal to the computer that this is a separate block of code under the control of the if statement.

Speaking of rudimentary intelligence, we could use this syntax to write a program that spares us the trouble of deciding what to eat each week:
#!/usr/bin/python
checkingAccountBalance = 4
 
if checkingAccountBalance < 10:
     thisWeeksFood = 'ramen'
if checkingAccountBalance >= 10:
     thisWeeksFood = 'goodRamen'
 
print "We are eating %s this week" % (thisWeeksFood)
 
# similarly
if checkingAccountBalance == 15:
     thisWeeksFood = 'that particular brand of good ramen'
 
if checkingAccountBalance != 15:
     thisWeeksFood = 'certainly _not_ that brand!'
     # if statements can contain more than one command
     print 'absolutely not!'
 
 
 

We'd like to clean that up a bit-- not only is that "checking_account_balance <= 10" a pile of unnecessary keystrokes, but it could also hurt us down the road. For instance, what if inflation pushed up the price of good ramen? We'd want to change out cutoff point-- to twelve bucks, for instance. However, if we changed one of the numbers but forgot to change the second, we'd have a bug in our code. By making our program simpler we can avoid such mistakes, and we can make things simpler by using python's 'else' statement.
if checkingAccountBalance < 10:
     thisWeeksFood = 'ramen'
else:
     thisWeeksFood = 'goodRamen'

But what if there's a third option? or a fourth? This is taken care of by python's 'elif' (short for "else if") statement.
if checkingAccountBalance < 10:
    thisWeeksFood = 'ramen'
elif checkingAccountBalance < 100:
    thisWeeksFood = 'good ramen'
elif checkingAccountBalance < 200:
    thisWeeksFood = 'better ramen'
else:
    thisWeeksFood = 'ramen that is truly profound in its goodness'

And now we know what to eat for dinner.

What is the nature of truth? Sneaking philosophy into computer science


But what is 'truth', anyway? Here we have a simple statement-- "less than"-- and so it's meaning is quite intuitive. But truth has a formal meaning in python, as it does in all programming languages. In short:

any nonzero number or nonempty object -> true
zero numbers, empty objects, and the special objects None and False -> false
if 1:
print "True!"
 
if 0:
    print "True!"
else:
    print "False!"
 

Of course, these operations are more useful with variables instead of straight numbers.
s = 0
if s:
    print "s is true!"
else:
    print "s is false!"

What if we want s to evaluate to true if s is zero?
s = 0
if s == 0:
    print "s is true!"
else:
    print "s is false!"
 

Non-empty strings are always true, no matter their content.
s = ""
if s:
    print "Your instructor has done something wrong"
else:
    print "'s' is surely not true, because 's' is empty."
 
 
s = "Rich is the greatest python teacher this world has ever seen"
if s:
    print "'%s' is true!" % s
else:
    print "'%s' is false!" % s

Python has abstract versions of truth and falsehood as well
s = 1 < 2
print s
 
if s:
    print "true!"
else:
    print "false!"
 
 
s = 5 < 3
print s
 
if s:
    print "true!"
else:
    print "false!"
 


It also has a third notion, None. This is rarer, and it evaluates to falsehood when in an if statement. We'll see more of it later when we talk about making your own functions.
s = None
if s:
    print "nothing is true!"
else:
    print "nothing is false!"

and/or/not
Finally, what if we want to combine two or more statements in a single line? Boolean operators can help us out. 'and' will only return true if both statements are true, while 'or' will return true if either statement is true. 'not' returns the inverse of the true/false nature of the statement it is given.
true_statement = 'truth itself'  # non-empty strings are true
false_statement = ''  # empty strings are false
 
if true_statement and false_statement:
    print "This should not print."
else:
    print "This should print"
 
if true_statement or false_statement:
    print "This should print"
 
 
if not false_statement:
    print "This should print"
 
if not (true_statement and false_statement):
    print "This should print"
 
However, 'and' and 'or' are a little more complicated than, for instance, the '>' and '==' operators that we're used to seeing in if statements. Let's look at 'and' first:
a = 5 < 3
print a
 
b = 1 and 1
print b
 
c = 1 and 0
print c
 
d = 1 and 2
print d
 
e = 2 and 1
print e
 
f = 0 and 2
print f
 
I think about this by imagining the computer as looking at each statement in turn, left to right, and being maximally lazy about the number of statements it wants to look at and maximally forgetful about the number of statements it has to remember. For instance, when it's given the 'd = 1 and 2' statement, it first looks at one, figures out that that's true, and then it checks the two-- only remembering the two, it returns that. It's the reverse case with the 'e = 2 and 1' statement: as it looks at the one second, it returns one. And finally with the 'f = 0 and 2' statement, it knows that the 'and' can't possibly be true if the first part is false, so it just returns the only thing that it has seen-- the zero.

'or' works in a similar manner:
g = 0 or 1
print g
 
h = 1 or 0
print h
 
i = 1 or 2
print i
 
j = 2 or 1
 
In the first case, the computer needs to see the second variable to evaluate the 'or', so it returns the second variable. In the second through fourth cases, it knows that the 'or' should be true after only seeing the first variable, and so it returns that.

Exercises

1. Some more truth exercises. Use the format:
query = <fill in blank>
if query:
    print 'Query is true'
else:
    print 'Query is false'
Try the following things in the blank. Are they true? If you don't see exactly why they are true or false, please ask a TA.
a) "" (the empty string)
b) []
c) {}
d) (a list containing an empty list)
e) 0
f) [0]
g) [0][0] (also-- what is this? Print out the value of [0][0] and [1][0] before doing the truth test)
h) [0]

2. Have the user input two numbers. If the numbers are equal, print the number back.

3. Modify your solution of exercise one such that if the numbers are not equal, print the first number that the user entered back. Use the 'else' statement.

4. Modify your solution of exercise two such that if the numbers are not equal, print the smaller number. Use the 'elif' statement.

5. Write your first gene-finding program: have the user enter a string of six nucleotides. If the length of the string is not six, tell the user to input another string. If it is, then create the four three-base substrings of this string. If any of these substrings is the sequence 'ATG', print the position of that substring. If none of the substrings match 'ATG', print -1.

Your gene finder isn't very good at finding genes yet, but it is good at motivating some of the things that you'll be learning about in the next two lectures: loops, which perform a single task over and over and over again, and python's text processing capabilities, which reduce the bulk of this program to a single line.

6. Write your first fasta parser: from a series of user inputs, you wish to create a dictionary keyed by gene IDs with values corresponding to their sequence. A fasta file has the following format:
>gene1
ATAGCAGTTAGC
TTAGCAGCAGTT
ATAGCGCA
>gene2
ATGACGACGATT
TTGACGACTAGG
ACAGCC
>gene3
AGATGCCCCCTT
...
While you will learn about handling files soon, for now, assume that this file is being typed in by the user-- their first input will be '>gene1', their second will be 'ATAGCAGTTAGC', and so on. Ask the user for input ten times. For each line input, you will have to determine whether it is a gene name or a sequence and act accordingly.

Your dictionary should have keys 'gene1', 'gene2', and 'gene2' (note the absence of the '>' symbol) and the sequences of those genes as values.

7. Replace "X" in this code with a statement that ensures that if the user entered "1", a "0" is printed, and if they entered a "0", a "1" is printed. Don't worry about other numbers.
s = raw_input("Enter a number: ")
s = int(s)
t = X
print t

Solutions
2.
#!/usr/bin/env python
 
a = int(raw_input('enter a number '))
b = int(raw_input('enter another number '))
 
if a == b:
    print a
 
3.
#!/usr/bin/env python
 
a = int(raw_input('enter a number '))
b = int(raw_input('enter another number '))
 
if a == b:
    print a
else:
    print a
 
4.
#!/usr/bin/env python
 
a = int(raw_input('enter a number '))
b = int(raw_input('enter another number '))
 
if a == b:
    print a
elif a < b:
    print a
elif b < a:
    print b
 
5.
#!/usr/bin/env python
 
seq = raw_input('Please Enter a String of 6 Nucleotides ')
 
if len(seq) != 6:
    seq = raw_input('Please Enter a String on _6_ (and only 6) Nu
cleotides ')
 
first = seq[0:3]
second = seq[1:4]
third = seq[2:5]
fourth = seq[3:]
 
if first == 'ATG':
    print 'The start codon starts at the first position'
elif second == 'ATG':
    print 'The start codon starts at the second position'
elif third == 'ATG':
    print 'The start codon starts at the third position'
elif fourth == 'ATG':
    print 'The start codon starts at the fourth position'
else:
    print -1
 
6.
#!/usr/bin/env python
 
dict = {}
line = raw_input("line:")
if line[0] == '>':
    key = line[1:]
    dict[key] = ''
else:
    dict[key] += line
line = raw_input("line:")
if line[0] == '>':
    key = line[1:]
    dict[key] = ''
else:
    dict[key] += line
line = raw_input("line:")
if line[0] == '>':
    key = line[1:]
    dict[key] = ''
else:
    dict[key] += line
line = raw_input("line:")
if line[0] == '>':
    key = line[1:]
    dict[key] = ''
else:
    dict[key] += line
line = raw_input("line:")
if line[0] == '>':
    key = line[1:]
    dict[key] = ''
else:
    dict[key] += line
line = raw_input("line:")
if line[0] == '>':
    key = line[1:]
    dict[key] = ''
else:
    dict[key] += line
line = raw_input("line:")
if line[0] == '>':
    key = line[1:]
    dict[key] = ''
else:
    dict[key] += line
line = raw_input("line:")
if line[0] == '>':
    key = line[1:]
    dict[key] = ''
else:
    dict[key] += line
line = raw_input("line:")
if line[0] == '>':
    key = line[1:]
    dict[key] = ''
else:
    dict[key] += line
line = raw_input("line:")
if line[0] == '>':
    key = line[1:]
    dict[key] = ''
else:
    dict[key] += line
print dict