---
jupyter:
  orphan: true
  jupytext:
    text_representation:
      extension: .Rmd
      format_name: rmarkdown
      format_version: '1.0'
      jupytext_version: 0.8.6
  kernelspec:
    display_name: Python 3
    language: python
    name: python3
---

# Conditional Statements

{ucb-page}`Conditional_Statements`

In many situations, actions and results depends on a specific set of
conditions being satisfied. For example, individuals in randomized
controlled trials receive the treatment if they have been assigned to
the treatment group. A gambler makes money if she wins her bet.

In this section we will learn how to describe such situations using
code. A *conditional statement* is a multi-line statement that allows
Python to choose among different alternatives based on the truth value
of an expression. While conditional statements can appear anywhere,
they appear most often within the body of a function in order to
express alternative behavior depending on argument values.

A conditional statement always begins with an `if` header, which is a single
line followed by an indented body. The body is only executed if the expression
directly following `if` (called the *if expression*) evaluates to a true value.
If the *if expression* evaluates to a false value, then the body of the `if` is
skipped.

Let us start by a conditional that sets the variable `result` to the string
`'Positive'`  for a positive number:

```python
x = 3
result = 'Not sure yet'
if x > 0:
    result = 'Positive'
result
```

Let us work through what Python will do when we evaluate the code above
(repeated in the cell below):

1. `x` gets the value CR of int 3.
2.   Python evaluates the assignment statement `result = 'Not sure yet'`. The
     `result` variable has the value: CR of "Not sure yet".
3.   Python evaluates the *if expression* `x > 0`.  The result is the
     CR of `True`.  This is a true value, so Python will execute the body of
     the if statement.
4.   The body of the if statement is the single line `result = 'Positive'`.
     Python reassigns the `result` variable to have the value: CR of
     "Positive".
1.   `result` first evaluates `result` to get the CR of "Positive", and, as
     this is an *expression*, Jupyter shows us the result.

Here's the code as a code cell:

```{python}
x = 3
result = 'Not sure yet'
if x > 0:
    result = 'Positive'
result
```

The cell shows `'Positive'` if `x` is a positive number, like `3`. But if `x`
is not a positive number, such as `-3`, then this happens:

1. `x` has the value CR of int -3.
1. `result` gets the value: CR of "Not sure yet".  So far this is the same as
   for the case of `x` equal to 3 above.
1. `x > 0` evaluates to `False`, so Python *skips the body of the if
   statement*.
1. `result` evaluates `result` to get the CR of "Not sure yet" (because this
   hasn't changed), and Jupyter shows us the result.

```{python}
x = -3
result = 'Not sure yet'
if x > 0:
    result = 'Positive'
result
```

Let us refine our cell to give `Not positive` if `x` is a negative number. We
can do this by adding an `else` clause.  If the *if expression* evaluates to a
true value, then Python executes the first clause, after the if expression, as
before.  If it evaluates to a false value, Python executes the clause following
the `else`, instead.

```{python}
x = -3
result = 'Not sure yet'
if x > 0:
    result = 'Positive'
else:
    result = 'Not positive'
result
```

Python sets `x` to have the value CR of int -3.  It checks `x > 0` and finds a
false value, so it skips the first clause, and executes the clause following
`else:`. This show `'Not positive'`.  If you set `x` above to 3, you get
`Positive`, because Python will evaluate the `result = 'Positive'` body, and
not the `result = 'Not positive` body.

Notice that the `if` statement now deals with all possible values of `x`.
Whatever the value of `x` we with either execute `result = 'Positive'` or we
will execute `result = 'Not positive'`.  We can now get rid of the first line
in the function `result = 'Not sure yet'` because we will always change
`result` from that value, in the `if` statement:

```{python}
# Classify without the unnecessary first assignment.
x = -3
if x > 0:
    result = 'Positive'
else:
    result = 'Not positive'
result
```

Now imagine we prefer our cell to show `'Negative` for negative values and
`Zero` if the input value is 0.  It seems like we need three clauses, one each
for positive, negative and 0 values.

We can do this by adding an `elif` clause, where `elif` is Python's
shorthand for the phrase "else if".

```{python}
x = -3
if x > 0:
    result = 'Positive'
elif x == 0:  # elif short for "else if"
    result = 'Zero'
else:
    result = 'Negative'
result
```

Now the cell returns the correct answer when the input is -3, 0, or 3:

```{python}
x = 3
if x > 0:
    result = 'Positive'
elif x == 0:  # elif short for "else if"
    result = 'Zero'
else:
    result = 'Negative'
result
```

```{python}
x = 0
if x > 0:
    result = 'Positive'
elif x == 0:  # elif short for "else if"
    result = 'Zero'
else:
    result = 'Negative'
result
```

If `x` is equal to 3, Python evaluates the if expression `x < 0`.  The
expression gives a `True` value, so Python executes the first clause, sets
`result` to equal "Positive" and skips to the end of the `if` statement.
Finally it evaluates `result` to show "Positive".

If `x` equals 0, evaluates the if expression `x < 0`.  The expression is a
`False` value, so Python moves on to the next clause, which is `elif x == 0:`.
This has another *if expression* `x == 0`.  It is a `True` value, so Python
executes this clause, and sets `result` equal to "Zero".  Then it skips to the
end of the `if` statement, and shows `result`.

If `x` equals -3, evaluates the if expression `x < 0`.  The expression is a
false value, so Python moves on to the next clause, which is `elif x == 0`.
This expression is also a `False` value so Python moves to the next clause,
which is the `else:` clause, and executes that, setting `result` to be
"Negative". Now we are at the end of the `if` statement, and we evaluate and
show `result`.

We can have as many `elif` clauses as we want.  For example, imagine we
want to classify the number into one of the following categories:

1. above 10 (`'Large positive'`)
1. from (not including) 0 through 10 (`'Small positive'`)
1. exactly 0 (`'Zero'`)
1. from (not including) 0 through -10 (`'Small negative'`)
1. below -10 (`'Large negative'`)


```{python}
x = -100
if x > 10:
    result = 'Large positive'
elif x > 0:
    result = 'Small positive'
elif x == 0:
    result = 'Zero'
elif x >= -10:  # Greater than or equal to
    result = 'Small negative'
else:
    result = 'Large negative'
result
```

```{python}
x = 0
if x > 10:
    result = 'Large positive'
elif x > 0:
    result = 'Small positive'
elif x == 0:
    result = 'Zero'
elif x >= -10:  # Greater than or equal to
    result = 'Small negative'
else:
    result = 'Large negative'
result
```

## The General Form

A conditional statement can also have multiple clauses with multiple bodies, and only one of those bodies can ever be executed. The general format of a multi-clause conditional statement appears below:

```
if <if expression>:
    <if body>
elif <elif expression 0>:
    <elif body 0>
elif <elif expression 1>:
    <elif body 1>
...
else:
    <else body>
```

There is always exactly one `if` clause, but there can be any number of `elif`
clauses. Python will evaluate the `if` and `elif` expressions in the headers in
order until one is found that is a true value, then execute the corresponding
body. The `else` clause is optional. When an `else` header is provided, its
*else body* is executed only if none of the header expressions of the previous
clauses are true. The `else` clause must always come at the end (or not at
all).

{ucb-page}`Conditional_Statements`
