Now we learn how to handle decision making, and repetitions in programming. Controls or decision making in programming require the programmer to specify if one or more conditions to be evaluated, are present. As shown here a flowchart for a control would specify the condition to be tested by the program and along with a statement, or block of statements, to be executed if the condition is determined to be true. And optionally, other statements to be executed if the condition is determined to be false. In consequence, controls allow non-sequential execution of comments. A pseudocode associated with a control will have the form, if condition, meaning that condition is true, then execute some code. Else, if condition is false, execute some different code. If and else are two key words encountered in many programming languages to specify controls. Let's see an example of how an if statement will work in Python. Suppose we ask the user to enter a DNA sequence for a variable called dna. As we learned in a previous lecture we need to use the function input in Python 3 or raw_input in Python 2. Here we show it with input. After the user enters the sequence, we want to check if it contains any undefined characters. How do you do this? We need to use the if statement that would check if character n is in the variable dna. If this condition is true, then let's say we want to count how many character Ns are there by calling the method count for the string object dna. And store the answer in a variable nbases, that later we can print with the built in function, print. Now, note how the if statement is structured. The keyword, if, is followed by the condition n in dna, and then by a colon. On the next line, we start the block of code to execute if the condition is true. This block is specified by always allowing the same number of spaces or indentation in front of each statement of the block. After typing in the if statement Python will give us the answer. In this case dna sequence has three undefined bases. The conditions that follow the if keyword are called Boolean expressions. This means that they are either true or false. Let's check a few Boolean expressions in Python. 0 < 1 will give the answer true, of course. We can have more complicated expression using built-in functions or functions that we wrote ourself. But we'll learn later how to write them. For instance, let's call now a built-in function, the function len, len('atgcgt') >= 10 will obviously give the answer false. In general Boolean expressions are formed with the help of the comparison, identity, and membership operators which we'll see more in detail next. Comparison operators compare values of variables. To test if these values are equal you use the double equal sign operator. Let's see an example of this. a == A will give the answer for us. Notice that the equality is not tested by one single equal sign as it is in math. As we learned before, one single equal sign represents an assignment operation, while two double equal signs represent a logical operator. We can also test if two values are different by using the != operator. String 'GT' != 'AG' will return a true value because that those strings are different. We can test if a value is less, greater, less or equal, or great or equal than another value by using the less than or bigger than signs. Or a combination of these with the equal sign. For instance, character A less than character C returns true. Here Python used an alphabetical order to determine the value of this Boolean expression. We can include operations in our Boolean expression which Python will have to first evaluate. For instance, let's do 10 + 1 == 11, which will obviously return true. In and not in are membership operators. You can use in to test if a variable is present in a sequence, and not in if you want to test if that variable is not present in the sequence. Let's see an example again. Assume motif is a string containing A, C, G, Ts characters as before. Suppose we want to test if motif is contained in another string variable called dna. When we type motif in dna, Python will look for the string motif in variable dna and because it finds it, it will return the Boolean value true. The identity operators, is and is not, test if two variables on either side of them point or don't point respectively to the same oject. At first glance the operator is seems to be exactly the same thing as the comparison operator == which tests if two variables have the same value. Let's take an example where we can see that actually the operator is different from the == operator. Suppose we have a list variable called alphabet that contains the letters a, c, g, and t. We learned how to create a copy of the list alphabet by using a slice operator. We basically say the name of the list, alphabet, and then give it a slice or two square brackets that contain just the colon. Let's call this copy new alphabet. When we test if alphabet is equal using the == operator, we find out that these two lists are equal, but when we use the is operator the answer is false. Why is this? Remember the slice operator creates a new list actually, which is a copy of the initial list, therefore it is a completely new object. And, even though it's created with the same elements, it's in a different location in the memory than the initial list. And therefore it is a completely different object that can now be modified independently from the initial one. If we want to specify what happens if the condition is not true in our problem, we use and if else statement. For instance, let's say that, as before, if the dna variable doesn't contain any Ns, meaning that the DNA sequence that has entered has no undefined bases. We want to print the number of them. But if there are no such n characters then we want to print a message that will let the user know that there are no undefined bases. The Python syntax for this requires that, the if statement called is followed by the keyword else. Notice how the else keyword needs to be aligned to the if keyword. And followed by a colon and on the next line by the code of statements to execute if the condition is not true. In our case, print('dna sequence has no undefined bases'). Sometimes it is convenient to test several conditions in one if structure. This is equivalent to testing a second condition if the initial condition is not true, as illustrated in this flow chart. In Python, you can specify more than one alternate condition by using the elif statement. So if condition 1 is true, then do some action. If it is not true, we use elif to test the second condition, called condition 2. Do some other action, if condition 2 is not true, then we can use elif again. To test the third condition, and so on, and so on, until no more conditions remain to be tested. We can also specify what happens if none of the condition tested are true by using an else statement as before. Let's get back to our program to test if there are undefined bases in our DNA sequence. First, we test if there are any n characters in the sequence. If there aren't Ns we print the message that the DNA sequence has undefined bases. What happens if the user introduces the DNA sequence using uppercase letters instead of lowercase letters? In that case, testing for lowercase n will be false for our if condition. And therefore, the DNA sequence has undefined bases will not print it. So we could test if upper case N is in the sequence. So we use and elif statement, elif and N is present in the variable DNA. Then again, we print DNA sequence as undefined basis. If none of them are present, then we use an else statement. And then we print the DNA sequence has no undefined bases. Notice how this program doesn't count how many undefined bases there are there. We could count the number of lower and upper cases of n separately. But what if both of them are present? We'll need to combine the two conditions somehow so that they can test both cases at the same time. We can do this with the help of logical operators. To test if two conditions are both true, we need to use the and operator. To test if at least one condition is true we'll use the or operator. Not is a negation operator that equals true only if condition tested is false. Let's get back to our small example. To combine the testing of the presence of both lower and uppercase N in DNA, we can use the or operator. So, if 'n' in dna or 'N' in dna, then, we can actually count the number of undefined bases. The variable nbase is we can use it now to store both the counts for the small case n and big case N. And then we can print how many undefined bases are in the dna sequence. Else we just print the DNA sequence has no undefined bases.