Comp 112

Lecture 4

Flow Control

2017.09.26

Sometimes we want to do something

*contingent*on something else.We can use the values of boolean type to decide whether to do it.

In Python we do this with an

.`if`

statement`if <boolean_expression> : <first_conditional_statement> ⋮ <last_conditional_statement>`

The indented block of statements is called a

**branch**.The boolean expression above it is called the

**branch guard**.If the branch guard evaluates to

`True`

then the branch is run.Otherwise, it is skipped.

Sometimes we want one of two things to happen, depending on some condition.

We could write:

`if <guard_condition> : <true_branch> if not <guard_condition> : <false_branch>`

But this pattern is so common that it has a special syntax, the

:`else`

clause`if <guard_condition> : <true_branch> else : <false_branch>`

If the guard condition evaluates to

`True`

then the**true branch**is run.Otherwise, the

**false branch**is run.So

*exactly one*branch is always run.

We can combine

`if`

and`else`

clauses to run the first branch whose guard is satisfied:`if <first_condition> : <first_branch> else : if <second_condition> : <second_branch> else : ⋮ else: if <last_condition> : <last_branch>`

But this pattern is so common that it also has a special syntax, the

:`elif`

clause`if <first_condition> : <first_branch> elif <second_condition> : <second_branch> ⋮ elif <last_condition> : <last_branch>`

The branch guards are tested in order.

Only the branch corresponding to the

*first*guard that evaluates to`True`

is run.Like an if statement,

*at most one*branch is run.

We can add an `else`

clause to a chained conditional:

```
if <first_condition> :
<first_branch>
elif <second_condition> :
<second_branch>
⋮
elif <last_condition> :
<last_branch>
else :
<default_branch>
```

The branch of the

`else`

clause is the**default branch**. It is run if all of the other branch guards evaluate to`False`

.Like an if-else statement,

*exactly*branch is always run.This is equivalent to:

`if <first_condition> : <first_branch> elif <second_condition> : <second_branch> ⋮ elif <last_condition> : <last_branch> elif True : <default_branch>`

`if`

StatementsThe most general form of an `if`

statement has:

exactly one

`if`

clause,zero or more

`elif`

clauses,zero or one

`else`

clauses.

Let’s think of something and have Python guess what it is.

```
def guessing_game () :
if input ('is it an animal? ') == 'yes' :
if input ('does it have legs? ') == 'yes' :
print ('then it must be a centipede!')
else :
print ('then it must be a shark!')
elif input ('is it a vegetable? ') == 'yes' :
if input ('does your mom make you eat it? ') == 'yes' :
print ('then it must be broccoli!')
else :
print ('then it must be a pumpkin!')
elif input ('is it a mineral? ') == 'yes' :
if input ('is it shiny? ') == 'yes' :
print ('then it must be gold!')
else :
print ('then it must be mud!')
else :
print ('then I give up!')
```

The branching structure of conditionals can be arbitrarily complex.

But complicated conditional statements can get confusing.

```
def leap_deep (year) :
if year % 4 == 0 :
if year % 100 == 0 :
if year % 400 == 0 :
print (str (year) + ' is a leap year')
else :
print (str (year) + ' is not a leap year')
else :
print (str (year) + ' is a leap year')
else :
print (str (year) + ' is not a leap year')
```

Boolean expressions are useful to simplify conditional structure.

```
def leap_flat (year) :
if (year % 4 == 0 and year % 100 != 0) or year % 400 == 0 :
print (str (year) + ' is a leap year')
else :
print (str (year) + ' is not a leap year')
```

You can also write **conditional expressions**:

`<true_expression> if <boolean_guard> else <false_expression>`

like:

```
def min (x , y) :
return x if x <= y else y
```

instead of:

```
def min (x , y) :
if x <= y :
return x
else :
return y
```

An

`if`

statement executes a code block*at most one time*, depending on whether the guard is satisfied.Another control structure, called a

, executes a block`while`

statement*any number of times*, as long as the guard is satisfied.`while <boolean_expression> : <first_block_statement> ⋮ <last_block_statement>`

The indented block of statements is called the

**loop body**.The boolean expression above it is called the

**loop guard**.

When control reaches a `while`

statement:

- The guard is evaluated.
- If the guard’s value is
`False`

then the body is skipped. - Otherwise, control passes into the body.
- Control flows normally within the body.
- After the last statement of the body, control returns to the guard, and this process is repeated.

We can compute the factorial (mathematical) function (i.e. $n! = n × (n−1) × (n−2) × ⋯ × 1$) by iteration.

```
def factorial (n) :
"""
signature: int -> int
precondition: n >= 0
returns the factorial of the argument
"""
acc = 1
while n > 0 :
acc = acc * n
n = n - 1
return acc
```

The variable “

`n`

” is a**loop variable**.It is part of the guard and gets updated during the body of the loop.

The variable “

`acc`

” is an**accumulator**.It stores the running partial result of the value computed by the loop.

When we’re finished repeating the loop the accumulator should contain the value we want.

In the loop body of the factorial function we updated both the loop variable and the accumulator based on their previous values.

There is a shorthand for this common pattern:

`def factorial (n) : acc = 1 while n > 0 : acc *= n # same as: acc = acc * n n -= 1 # same as: n = n - 1 return acc`

The expressions “

`acc *= n`

” and “`n -= 1`

” are called**augmented assignments**.They are shorthand for “

`acc = acc * n`

” and “`n = n - 1`

” respectively.There are augmented assignment forms for the operators

`{+ , - , * , / , // , % , **}`

.

Last week we learned how to draw a square using Python’s

**turtle**:`def square (size) : turtle.forward (size) turtle.left (90.0) turtle.forward (size) turtle.left (90.0) turtle.forward (size) turtle.left (90.0) turtle.forward (size) turtle.left (90.0)`

This got pretty repetitive.

We can streamline this definition using a

`while`

loop.

```
def square (size) :
sides_drawn = 0
while sides_drawn < 4 :
turtle.forward (size)
turtle.left (90.0)
sides_drawn += 1
```

Using loops and conditionals together we can validate user input:

A

*predicate*function for days of the week:`def is_weekday (day) : """ signature: str -> bool """ return \ day == 'Sunday' or day == 'Monday' or day == 'Tuesday' or day == 'Wednesday' or \ day == 'Thursday' or day == 'Friday' or day == 'Saturday'`

A function to take valid input from the user:

`def get_day_of_week () : """ signature: () -> str ; returns a day of the week entered by the user and validated by is_weekday. """ while True : day = input ('What day is it (Sunday through Saturday)? ') if is_weekday (day) : return day else : print ('Sorry, but "' + day + '" is not a day of the week.')`

A function that decides what to do based on user input:

`def what_to_do () : """ signature: () -> NoneType """ day = get_day_of_week () # here we know that day will be a valid day of the week if day == 'Saturday' or day == 'Sunday' : print ("I'm sleeping in.") else : print ('Better get up and go to class.')`

Reading:

- section 5.4–5.7: if statements (2 pages)
- sections 7.3–7.5: while statements (3 pages)
- sections 6.1–6.4: return values, debugging, function composition, boolean functions (4 pages)

Come to lab on Thursday.

Complete homework 4.