Decisions and Selection

• Boolean Values and Boolean Expressions
• need way to express the results of a comparison
• usually some form of True and False - how all computer logic works
• called Boolean values (George Boole) or Boolean constants or literals
• Python uses True, False - they are NOT strings (no quotes)
• relational operators (book calls them comparison operators)
• ==, !=, <=, <, >, >=
• compare all types of data (string to string, int to int, float to int, float to float)
• produce True or False
• note the difference between = and ==
• Logical operators
• and, or and not are logical (or Boolean) operators
• they work ONLY on Bools and produce another bool value
• truth tables for operators
PQP and Q P or Q
TrueTrueTrueTrue
TrueFalse FalseTrue
FalseTrueFalseTrue
FalseFalseFalseFalse
Pnot P
TrueFalse
FalseTrue
• watch out for expressions that are always True or always False! Python does not detect them!
```	"x > 5 or x < 8"
"x < 5 and x > 10"
```
• watch out for "x > 5 or 6"
• NOTE: "check your understanding 6.2.1" has an incorrect statement in its feedback. "0 < x < 5" IS a valid comparison in Python, but not most other languages
• Precedence of Operators
• This table comes from docs.python.org - highest precedence at top, lowest at bottom, some operators removed
OperatorsName
x[index], x[index:index], x(arguments...), x.attribute Subscription, slicing, call, attribute reference
** Exponentiation (right to left associative)
+x, -x, ~x Positive, negative, bitwise NOT
*, /, //, % Multiplication, division, remainder
+, - Addition and subtraction
in, not in, is, is not, <, <=, >, >=, !=, == Comparisons, including membership tests and identity tests
not x Boolean NOT
and Boolean AND
or Boolean OR
• So in an expression like a + b * 5 > z - 3**y, the exponentiation is done first, then the multiplication, then the addition and the subtraction, then the comparison, to finally result in a bool value
• Conditional Execution: Binary Selection
• need to make decisions
• result always expressed as True or False
• use an if statement to use this decision
• syntax
```		if boolean expression:
statements1
else:
statements2
```
• don't forget the colons after the boolean expression and the else
• indentation decides what is in "statements1" and "statements2"
• the blocks cannot be empty, can be as big as you like
• see flowchart in textbook for semantics
• See Monte Carlo simulation in textbook "Approximating Pi with Simulation"
• boolean expression is evaluated either True or False
• if True, then the statements1 are executed
• if False, then the statements2 are executed
• the other block is completely skipped
• then the next statement after the if statement is executed
• "Factor out"
• if a statement appears in BOTH the if and the else branch, consider taking it out of the if statement altogether.
• either put it before the if or after, depending on what it is doing
• shortcut in writing a boolean expression - don't have to say "if flag == True:", it is equivalent to just saying "if flag:"
• Omitting the else Clause: Unary Selection
• variation on the if statement
• you do not have to have the "else" branch
• if test is not true, nothing is done
• textbook has flowchart for semantics
• example:
```	if x > y:
t = x
x = y
y = t
```

what does it do?
• Nested conditionals
• can nest one if statement inside another
• the indentation tells which else goes with which if
indentation is important!
```	if a > 5:
if b < 10:
print ("green")
else:
print("blue")

versus

if a > 5:
if b < 10:
print("green")
else:
print("blue")
```
• this structure is most useful when you have a set of conditions which covers ALL possibilities
• see flowchart in textbook
• does not have to end with a plain "else:" but it can
• if have plain else at end, it catches all values which did not match any of the tests above (kind of "default" case)
• more efficient than having a bunch of separate ifs - as soon as one is found that is true, the rest are skipped
• do NOT have to repeat tests in later if's which were already found to be true! do not do this!
``` 	example:
if x > 50:
grade = "A"
else:
if x <= 50 and x > 30:  #the x <= 50 MUST be true! don't test again!
grade = "B"
```
• example: quadrant on Cartesian plane
• Chained conditionals
• if you have a lot of nested if's, they can stretch across the screen
• special keyword to prevent this "elif"
• combination of "else" and "if"
• equivalent to
```   else:
if ...
```
• lets you line them all up under the first if
• ```if  condition1:
action1
elif condition2:
action2
elif condition3:
action3
else:
default case
```
• doesn't give you any more ability to do anything but looks nicer on screen
• Notes on 6.7.1 question
• choice I has a syntax error so it will not run
• choice II has some extra parentheses it does not need around the condition, but that does not break any syntax rules
• pay attention to what choice III is - it is not at all the same as choice II. It is two if statements, not one. Choice II is only one statement - all the phrases are tied together. Choice III has one if with NO else, then another if statement with an else.
• Boolean Functions
• functions can return Boolean values
• usually name them as questions "isError" or "canFind"
• "return x == 0" would test x (assumed to be the parameter) and return True if x was 0, False otherwise
• can call any function in the condition of an if, including Boolean functions
```	if isPrime(num):
print("it's good!")
```
• don't have to say "isPrime(num) == True" - this means the same as the example
• the example in the textbook is dangerous - does not check for division by zero before it divides by y!
• PLEASE use ONE return statement in functions like this!

It is tempting to say
```		if x > 0:
return "positive"
else:
return "not positive"
```

But this breaks a rule of structured programming, for each structure to have ONE entrance and ONE EXIT!
• Instead use a variable to hold the result until the end and return the variable
```		if x > 0:
result = "positive"
else:
result = "not positive"
return result
```
• a boolean function should have a statement as part of its documentation that says "returns True if .... and False when ..."
• How to negate a logical expression (DeMorgan's Laws)
• sometimes have a complicated expression using several operators like "a > 5 and b < 7 or c == 5"
• you discover that you actually need the negative of the expression
• you can use the not operator and parentheses to get the reverse like "not (a > 5 and b < 7 or c == 5)"
• OR you can "carry through" the not through the whole expression
• DeMorgan's Laws not (a and b) is equivalent to (not a or not b)
• and not (a or b) is equivalent to (not a and not b)
• so "not (a > 5 and b < 7 or c == 5)" is the same as "a <= 5 or b >= 7 and c != 5"
• Comparing strings
• also some discussion of this in Chapter 8 (Strings)
• relational operators work with strings too!
• compared by comparing ASCII codes of characters
• if all characters are equal, the 2 strings are equal. otherwise the string with the character with the smaller ASCII value is the "lesser" string
• space < digits < uppercase letters < lowercase letters
• " " < "0" < ... < "9" < "A" < ... < "Z" < "a" < ... < "z"
• Comparing float values
• because of errors in representation of float numbers, do not compare floats for exact equality
• safer to compare for being "close enough"
• ```if abs(a - 5000) < 0.00001:
print("close enough")
```

Thinking about if's short set of slides about putting if's together