3. Control Statements

Objectives

In this chapter, you’ll:

Image Make decisions with if, if else and if elif else.

Image Execute statements repeatedly with while and for.

Image Shorten assignment expressions with augmented assignments.

Image Use the for statement and the built-in range function to repeat actions for a sequence of values.

Image Perform sentinel-controlled iteration with while.

Image Create compound conditions with the Boolean operators and, or and not.

Image Stop looping with break.

Image Force the next iteration of a loop with continue.

Image Use functional-style programming features to write scripts that are more concise, clearer, easier to debug and easier to parallelize.

Outline

3.1 Introduction

In this chapter, we present Python’s control statements—if, if else, if elif else, while, for, break and continue. You’ll use the for statement to perform sequence-controlled- iteration—you’ll see that the number of items in a sequence of item determines the for statement’s number of iterations. You’ll use the built-in function range to generate sequences of integers.

We’ll show sentinel-controlled iteration with the while statement. You’ll use the Python Standard Library’s Decimal type for precise monetary calculations. We’ll format data in f-strings (that is, format strings) using various format specifiers. We’ll also show the Boolean operators and, or and not for creating compound conditions. In the Intro to Data Science section, we’ll consider measures of central tendency—mean, median and mode—using the Python Standard Library’s statistics module.

3.2 Control Statements

Python provides three selection statements that execute code based on a condition that evaluates to either True or False:

  • The if statement performs an action if a condition is True or skips the action if the condition is False.

  • The if... else statement performs an action if a condition is True or performs a different action if the condition is False.

  • The if... elif... else statement performs one of many different actions, depending on the truth or falsity of several conditions.

Anywhere a single action can be placed, a group of actions can be placed.

Python provides two iteration statementswhile and for:

  • The while statement repeats an action (or a group of actions) as long as a condition remains True.

  • The for statement repeats an action (or a group of actions) for every item in a sequence of items.

Keywords

The words if, elif, else, while, for, True and False are Python keywords. Using a keyword as an identifier such as a variable name is a syntax error. The following table lists Python’s keywords.

Python keywords

and

as

assert

async

await

break

class

continue

def

del

elif

else

except

False

finally

for

from

global

if

import

in

is

lambda

None

nonlocal

not

or

pass

raise

return

True

try

while

with

yield

3.3 if Statement

Let’s execute a Python if statement:

In [1]: grade = 85
In [2]: if grade >= 60:
   ...:     print('Passed')
   ...:    
Passed

The condition grade >= 60 is True, so the indented print statement in the if’s suite displays 'Passed'.

Suite Indentation

Indenting a suite is required; otherwise, an IndentationError syntax error occurs:

In [3]: if grade >= 60:
   ...: print('Passed')  # statement is not indented properly
  File "<ipython-input-3-f42783904220>",   line 2
    print('Passed')  # statement is   not indented properly
        ^
IndentationError: expected   an indented block

An IndentationError also occurs if you have more than one statement in a suite and those statements do not have the same indentation:

In [4]: if grade >= 60:
   ...:     print('Passed')  # indented 4 spaces
   ...:   print('Good job!)  # incorrectly indented only two spaces
  File <ipython-input-4-8c0d75c127bf>, line 3
    print('Good job!)  #   incorrectly indented only two spaces
    ^
IndentationError: unindent does not match any outer indentation level

Sometimes error messages may not be clear. The fact that Python calls attention to the line is usually enough for you to figure out what’s wrong. Apply indentation conventions uniformly throughout your code—programs that are not uniformly indented are hard to read.

Every Expression Can Be Interpreted as Either True or False

You can base decisions on any expression. A nonzero value is True. Zero is False:

In [5]: if 1:
   ...:     print('Nonzero values are   true, so this will print')
   ...:    
Nonzero values are true, so this will print

In [6]: if 0:
   ...:     print('Zero is false, so this will not print')

In [7]:

Strings containing characters are True and empty strings ('', "" or """""") are False.

Confusing == and =

Using the equality operator == instead of = in an assignment statement can lead to subtle problems. For example, in this session, snippet [1] defined grade with the assignment:

      grade = 85

If instead we accidentally wrote:

      grade == 85

then grade would be undefined and we’d get a NameError. If grade had been defined before the preceding statement, then grade == 85 would simply evaluate to True or False, and not perform an assignment. This is a logic error.

3.4 if else and if elif else Statements

The if else statement executes different suites, based on whether a condition is True or False:

In [1]: grade = 85

In [2]: if grade >= 60:
   ...:     print('Passed')
   ...: else:
   ...:     print('Failed')
   ...:    
Passed

The condition above is True, so the if suite displays 'Passed'. Note that when you press Enter after typing print('Passed'), IPython indents the next line four spaces. You must delete those four spaces so that the else: suite correctly aligns under the i in if.

The following code assigns 57 to the variable grade, then shows the if else statement again to demonstrate that only the else suite executes when the condition is False:

In [3]: grade = 57

In [4]: if grade >= 60:
   ...:     print('Passed')
   ...: else:
   ...:     print('Failed')
   ...:    
Failed

Use the up and down arrow keys to navigate backwards and forwards through the current interactive session’s snippets. Pressing Enter re-executes the snippet that’s displayed. Let’s set grade to 99, press the up arrow key twice to recall the code from snippet [4], then press Enter to re-execute that code as snippet [6]. Every recalled snippet that you execute gets a new ID:

In [5]: grade = 99

In [6]: if grade >= 60:
   ...:     print('Passed')
   ...: else:
   ...:     print('Failed')
   ...:    
Passed
Conditional Expressions

Sometimes the suites in an if else statement assign different values to a variable, based on a condition, as in:

In [7]: grade = 87

In [8]: if grade >= 60:
   ...:     result = 'Passed'
   ...: else:
   ...:     result = 'Failed'
   ...:    

We can then print or evaluate that variable:

In [9]: result
Out[9]: 'Passed'

You can write statements like snippet [8] using a concise conditional expression:

In [10]: result = ('Passed' if grade >= 60 else 'Failed')

In [11]: result
Out[11]: 'Passed'

The parentheses are not required, but they make it clear that the statement assigns the conditional expression’s value to result. First, Python evaluates the condition grade >= 60:

  • If it’s True, snippet [10] assigns to result the value of the expression to the left of if, namely 'Passed'. The else part does not execute.

  • If it’s False, snippet [10] assigns to result the value of the expression to the right of else, namely 'Failed'.

In interactive mode, you also can evaluate the conditional expression directly, as in:

In [12]: 'Passed' if grade >= 60 else 'Failed'
Out[12]: 'Passed'
Multiple Statements in a Suite

The following code shows two statements in the else suite of an if... else statement:

In [13]: grade = 49

In [14]: if grade >= 60:
    ...:     print('Passed')
    ...: else:
    ...:     print('Failed')
    ...:     print('You must take   this course again')
    ...:    
Failed
You must take this course again

In this case, grade is less than 60, so both statements in the else’s suite execute.

If you do not indent the second print, then it’s not in the else’s suite. So, that statement always executes, possibly creating strange incorrect output:

In [15]: grade = 100

In [16]: if grade >= 60:
    ...:     print('Passed')
    ...: else:
    ...:     print('Failed')
    ...: print('You must take this course again')
    ...:
Passed
You must take this course again
if... elif... else Statement

You can test for many cases using the if... elif... else statement. The following code displays “A” for grades greater than or equal to 90, “B” for grades in the range 80–89, “C” for grades 70–79, “D” for grades 60–69 and “F” for all other grades. Only the action for the first True condition executes. Snippet [18] displays C, because grade is 77:

In [17]: grade = 77

In [18]: if grade >= 90:
    ...:     print('A')
    ...: elif grade >= 80:
    ...:     print('B')
    ...: elif grade >= 70:
    ...:     print('C')
    ...: elif grade >= 60:
    ...:     print('D')
    ...: else:
    ...:     print('F')
    ...:
C

The first condition—grade >= 90—is False, so print('A') is skipped. The second condition—grade >= 80—also is False, so print('B') is skipped. The third condition—grade >= 70—is True, so print('C') executes. Then all the remaining code in the if... elif... else statement is skipped. An if... elif... else is faster than separate if statements, because condition testing stops as soon as a condition is True.

else Is Optional

The else in the if... elif... else statement is optional. Including it enables you to handle values that do not satisfy any of the conditions. When an if... elif statement without an else tests a value that does not make any of its conditions True, the program does not execute any of the statement’s suites—the next statement in sequence after the if... elif... statement executes. If you specify the else, you must place it after the last elif; otherwise, a SyntaxError occurs.

Logic Errors

The incorrectly indented code segment in snippet [16] is an example of a nonfatal logic error. The code executes, but it produces incorrect results. For a fatal logic error in a script, an exception occurs (such as a Zero-DivisionError from an attempt to divide by 0), so Python displays a traceback, then terminates the script. A fatal error in interactive mode terminates only the current snippet—then IPython waits for your next input.

3.5 while Statement

The while statement allows you to repeat one or more actions while a condition remains True. Let’s use a while statement to find the first power of 3 larger than 50:

In [1]: product = 3

In [2]: while product <= 50:
   ...:     product = product * 3
   ...:    

In [3]: product
Out[3]: 81

Snippet [3] evaluates product to see its value, 81, which is the first power of 3 larger than 50.

Something in the while statement’s suite must change product’s value, so the condition eventually becomes False. Otherwise, an infinite loop occurs. In applications executed from a Terminal, Anaconda Command Prompt or shell, type Ctrl + c or control + c to terminate an infinite loop. IDEs typically have a toolbar button or menu option for stopping a program’s execution.

3.6 for Statement

The for statement allows you to repeat an action or several actions for each item in a sequence of items. For example, a string is a sequence of individual characters. Let’s display 'Programming' with its characters separated by two spaces:

In [1]: for character in 'Programming':
   ...:     print(character, end='  ')
   ...:    
P  r  o  g  r  a  m  m  i  n  g 

The for statement executes as follows:

  • Upon entering the statement, it assigns the 'P' in 'Programming' to the target variable between keywords for and in—in this case, character.

  • Next, the statement in the suite executes, displaying character’s value followed by two spaces—we’ll say more about this momentarily.

  • After executing the suite, Python assigns to character the next item in the sequence (that is, the 'r' in 'Programming'), then executes the suite again.

  • This continues while there are more items in the sequence to process. In this case, the statement terminates after displaying the letter 'g', followed by two spaces.

Using the target variable in the suite, as we did here to display its value, is common but not required.

Function print’s end Keyword Argument

The built-in function print displays its argument(s), then moves the cursor to the next line. You can change this behavior with the argument end, as in

print(character, end='  ')

which displays character’s value followed by two spaces. So, all the characters display horizontally on the same line. Python calls end a keyword argument, but end itself is not a Python keyword. Keyword arguments are sometimes called named arguments. The end keyword argument is optional. If you do not include it, print uses a newline (' ') by default. The Style Guide for Python Code recommends placing no spaces around a keyword argument’s =.

Function print’s sep Keyword Argument

You can use the keyword argument sep (short for separator) to specify the string that appears between the items that print displays. When you do not specify this argument, print uses a space character by default. Let’s display three numbers, each separated from the next by a comma and a space, rather than just a space:

In [2]: print(10, 20, 30, sep=', ')
10, 20, 30

To remove the default spaces, use sep='' (that is, an empty string).

3.6.1 Iterables, Lists and Iterators

The sequence to the right of the for statement’s in keyword must be an iterable—that is, an object from which the for statement can take one item at a time until no more items remain. Python has other iterable sequence types besides strings. One of the most common is a list, which is a comma-separated collection of items enclosed in square brackets ([ and ]). The following code totals five integers in a list:

In [3]: total = 0

In [4]: for number in [2, -3, 0, 17, 9]:
   ...:     total = total + number
   ...:    

In [5]: total
Out[5]: 25

Each sequence has an iterator. The for statement uses the iterator “behind the scenes” to get each consecutive item until there are no more to process. The iterator is like a bookmark—it always knows where it is in the sequence, so it can return the next item when it’s called upon to do so. We cover lists in detail in the “Sequences: Lists and Tuples” chapter. There, you’ll see that the order of the items in a list matters and that a list’s items are mutable (that is, modifiable).

3.6.2 Built-In range Function

Let’s use a for statement and the built-in range function to iterate precisely 10 times, displaying the values from 0 through 9:

In [6]: for counter in range(10):
   ...:     print(counter, end=' ')
   ...:    
0 1 2 3 4 5 6 7 8 9

The function call range(10) creates an iterable object that represents a sequence of consecutive integers starting from 0 and continuing up to, but not including, the argument value (10)—in this case, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9. The for statement exits when it finishes processing the last integer that range produces. Iterators and iterable objects are two of Python’s functional-style programming features. We’ll introduce more of these throughout the book.

Off-By-One Errors

A common type of off-by-one error occurs when you assume that range’s argument value is included in the generated sequence. For example, if you provide 9 as range’s argument when trying to produce the sequence 0 through 9, range generates only 0 through 8.

3.7 Augmented Assignments

Augmented assignments abbreviate assignment expressions in which the same variable name appears on the left and right of the assignment’s =, as total does in:

for number in [1, 2, 3, 4, 5]:
total = total + number

Snippet [2] reimplements this using an addition augmented assignment (+=) statement:

In [1]: total = 0

In [2]: for number in [1, 2, 3, 4, 5]:
   ...:     total += number  # add number to total
   ...:    

In [3]: total
Out[3]: 15

The += expression in snippet [2] first adds number’s value to the current total, then stores the new value in total. The table below shows sample augmented assignments:

Augmented assignment

Sample expression

Explanation

Assigns

Assume: c = 3, d = 5, e = 4, f = 2, g = 9, h = 12

+=

c += 7

c = c + 7

10 to c

-=

d -= 4

d = d - 4

1 to d

*=

e *= 5

e = e * 5

20 to e

**=

f **= 3

f = f ** 3

8 to f

/=

g /= 2

g = g / 2

4.5 to g

//=

g //= 2

g = g // 2

4 to g

%=

h %= 9

h = h % 9

3 to h

3.8 Sequence-Controlled Iteration; Formatted Strings

This section and the next solve two class-averaging problems. Consider the following requirements statement:

A class of ten students took a quiz. Their grades (integers in the range 0 – 100) are 98, 76, 71, 87, 83, 90, 57, 79, 82, 94. Determine the class average on the quiz.

The following script for solving this problem keeps a running total of the grades, calculates the average and displays the result. We placed the 10 grades in a list, but you could input the grades from a user at the keyboard (as we’ll do in the next example) or read them from a file (as you’ll see how to do in the “Files and Exceptions” chapter). We show how to read data from SQL and NoSQL databases in Chapter 16.

 1 # class_average.py
 2 """Class average program with sequence-controlled iteration."""
 3
 4 # initialization phase
 5 total = 0  # sum of grades
 6 grade_counter =   0 
 7 grades = [98, 76, 71, 87, 83, 90, 57, 79, 82, 94]  # list of 10 grades
 8
 9 # processing phase
 10 for grade in grades: 
 11     total +=   grade  # add current grade to the running total
 12     grade_counter   += 1  # indicate that   one more grade was processed
 13
 14 # termination phase
 15 average = total / grade_counter
 16 print(f'Class average is {average}')
Class average is 81.7

Lines 5–6 create the variables total and grade_counter and initialize each to 0. Line 7

grades = [98, 76, 71, 87, 83, 90, 57, 79, 82, 94]  # list of 10 grades

creates the variable grades and initializes it with a list of 10 integer grades.

The for statement processes each grade in the list grades. Line 11 adds the current grade to the total. Then, line 12 adds 1 to the variable grade_counter to keep track of the number of grades processed so far. Iteration terminates when all 10 grades in the list have been processed. The Style Guide for Python Code recommends placing a blank line above and below each control statement (as in lines 8 and 13). When the for statement terminates, line 15 calculates the average and line 16 displays it. Later in this chapter, we use functional-style programming to calculate the average of a list’s items more concisely.

Introduction to Formatted Strings

Line 16 uses the following simple f-string (short for formatted string) to format this script’s result by inserting the value of average into a string:

f'Class average is {average}'

The letter f before the string’s opening quote indicates it’s an f-string. You specify where to insert values by using placeholders delimited by curly braces ({ and }). The placeholder

{average}

converts the variable average’s value to a string representation, then replaces {average} with that replacement text. Replacement-text expressions may contain values, variables or other expressions, such as calculations or function calls. In line 16, we could have used total / grade_counter in place of average, eliminating the need for line 15.

3.9 Sentinel-Controlled Iteration

Let’s generalize the class-average problem. Consider the following requirements statement:

Develop a class-averaging program that processes an arbitrary number of grades each time the program executes.

The requirements statement does not state what the grades are or how many there are, so we’re going to have the user enter the grades. The program processes an arbitrary number of grades. The user enters grades one at a time until all the grades have been entered, then enters a sentinel value (also called a signal value, a dummy value or a flag value) to indicate that there are no more grades.

Implementing Sentinel-Controlled Iteration

The following script solves the class average problem with sentinel-controlled iteration. Notice that we test for the possibility of division by zero. If undetected, this would cause a fatal logic error. In the “Files and Exceptions” chapter, we write programs that recognize such exceptions and take appropriate actions.

 1 # class_average_sentinel.py
 2 """Class average program with sentinel-controlled iteration."""
 3
 4 # initialization phase
 5 total = 0  # sum of grades
 6 grade_counter = 0  # number of grades   entered
 7
 8 # processing phase
 9 grade = int(input('Enter grade, -1 to end: '))  # get one grade
 10
 11 while grade != -1:
 12     total += grade
 13     grade_counter += 1
 14     grade = int(input('Enter grade, -1 to end: '))
 15
 16 # termination phase
 17 if grade_counter != 0:
 18     average = total / grade_counter
 19     print(f'Class average is {average:.2f}')
 20 else:
 21     print('No grades were entered')
Enter grade, -1 to end: 97
Enter grade, -1 to end: 88
Enter grade, -1 to end: 72
Enter grade, -1 to end: -1
Class average is 85.67
Program Logic for Sentinel-Controlled Iteration

In sentinel-controlled iteration, the program reads the first value (line 9) before reaching the while statement. The value input in line 9 determines whether the program’s flow of control should enter the while’s suite (lines 12–14). If the condition in line 11 is False, the user entered the sentinel value (-1), so the suite does not execute because the user did not enter any grades. If the condition is True, the suite executes, adding the grade value to the total and incrementing the grade_counter.

Next, line 14 inputs another grade from the user and the condition (line 11) is tested again, using the most recent grade entered by the user. The value of grade is always input immediately before the program tests the while condition, so we can determine whether the value just input is the sentinel before processing that value as a grade.

When the sentinel value is input, the loop terminates, and the program does not add –1 to total. In a sentinel-controlled loop that performs user input, any prompts (lines 9 and 14) should remind the user of the sentinel value.

Formatting the Class Average with Two Decimal Places

This example formatted the class average with two digits to the right of the decimal point. In an f-string, you can optionally follow a replacement-text expression with a colon (:) and a format specifier that describes how to format the replacement text. The format specifier .2f (line 19) formats the average as a floating-point number (f) with two digits to the right of the decimal point (.2). In this example, the sum of the grades was 257, which, when divided by 3, yields 85.666666666.... Formatting the average with .2f rounds it to the hundredths position, producing the replacement text 85.67. An average with only one digit to the right of the decimal point would be formatted with a trailing zero (e.g., 85.50). The chapter “Strings: A Deeper Look” discusses many more string-formatting features.

3.10 Built-In Function range: A Deeper Look

Function range also has two- and three-argument versions. As you’ve seen, range’s one-argument version produces a sequence of consecutive integers from 0 up to, but not including, the argument’s value. Function range’s two-argument version produces a sequence of consecutive integers from its first argument’s value up to, but not including, the second argument’s value, as in:

In [1]: for number in range(5, 10):
   ...:     print(number, end=' ')
   ...:    
5 6 7 8 9

Function range’s three-argument version produces a sequence of integers from its first argument’s value up to, but not including, the second argument’s value, incrementing by the third argument’s value, which is known as the step:

In [2]: for number in range(0, 10, 2):
   ...:     print(number, end=' ')
   ...:    
0 2 4 6 8

If the third argument is negative, the sequence progresses from the first argument’s value down to, but not including the second argument’s value, decrementing by the third argument’s value, as in:

In [3]: for number in range(10, 0, -2):
   ...:     print(number, end=' ')
   ...:    
10 8 6 4 2

3.11 Using Type Decimal for Monetary Amounts

In this section, we introduce Decimal capabilities for precise monetary calculations. If you’re in banking or other fields that require “to-the-penny” accuracy, you should investigate Decimal’s capabilities in depth.

For most scientific and other mathematical applications that use numbers with decimal points, Python’s built-in floating-point numbers work well. For example, when we speak of a “normal” body temperature of 98.6, we do not need to be precise to a large number of digits. When we view the temperature on a thermometer and read it as 98.6, the actual value may be 98.5999473210643. The point here is that calling this number 98.6 is adequate for most body-temperature applications.

Floating-point values are stored in binary format (we introduced binary in the first chapter and discuss it in depth in the online “Number Systems” appendix). Some floating-point values are represented only approximately when they’re converted to binary. For example, consider the variable amount with the dollars-and-cents value 112.31. If you display amount, it appears to have the exact value you assigned to it:

In [1]: amount = 112.31

In [2]: print(amount)
112.31

However, if you print amount with 20 digits of precision to the right of the decimal point, you can see that the actual floating-point value in memory is not exactly 112.31—it’s only an approximation:

In [3]: print(f'{amount:.20f}')
112.31000000000000227374

Many applications require precise representation of numbers with decimal points. Institutions like banks that deal with millions or even billions of transactions per day have to tie out their transactions “to the penny.” Floating-point numbers can represent some but not all monetary amounts with to-the-penny precision.

The Python Standard Library1 provides many predefined capabilities you can use in your Python code to avoid “reinventing the wheel.” For monetary calculations and other applications that require precise representation and manipulation of numbers with decimal points, the Python Standard Library provides type Decimal, which uses a special coding scheme to solve the problem of to-the-penny precision. That scheme requires additional memory to hold the numbers and additional processing time to perform calculations but provides the precision required for monetary calculations. Banks also have to deal with other issues such as using a fair rounding algorithm when they’re calculating daily interest on accounts. Type Decimal offers such capabilities.2

1https://docs.python.org/3.7/library/index.html.

2For more decimal module features, visit https://docs.python.org/3.7/library/decimal.html.

Importing Type Decimal from the decimal Module

We’ve used several built-in typesint (for integers, like 10), float (for floating-point numbers, like 7.5) and str (for strings like 'Python'). The Decimal type is not built into Python. Rather, it’s part of the Python Standard Library, which is divided into groups of related capabilities called modules. The decimal module defines type Decimal and its capabilities.

To use type Decimal, you must first import the entire decimal module, as in

          import decimal

and refer to the Decimal type as decimal.Decimal, or you must indicate a specific capability to import using from import, as we do here:

In [4]: from decimal import Decimal

This imports only the type Decimal from the decimal module so that you can use it in your code. We’ll discuss other import forms beginning in the next chapter.

Creating Decimals

You typically create a Decimal from a string:

In [5]: principal = Decimal('1000.00')

In [6]: principal
Out[6]: Decimal('1000.00')

In [7]: rate = Decimal('0.05')

In [8]: rate
Out[8]: Decimal('0.05')

We’ll soon use these variables principal and rate in a compound-interest calculation.

Decimal Arithmetic

Decimals support the standard arithmetic operators +, -, *, /, //, ** and %, as well as the corresponding augmented assignments:

In [9]: x = Decimal('10.5')

In [10]: y = Decimal('2')

In [11]: x + y
Out[11]: Decimal('12.5')

In [12]: x // y
Out[12]: Decimal('5')

In [13]: x += y

In [14]: x
Out[14]: Decimal('12.5')

You may perform arithmetic between Decimals and integers, but not between Decimals and floating-point numbers.

Compound-Interest Problem Requirements Statement

Let’s compute compound interest using the Decimal type for precise monetary calculations. Consider the following requirements statement:

A person invests $1000 in a savings account yielding 5% interest. Assuming that the person leaves all interest on deposit in the account, calculate and display the amount of money in the account at the end of each year for 10 years. Use the following formula for determining these amounts:

a = p(1 + r)n

where

p is the original amount invested (i.e., the principal),

r is the annual interest rate,

n is the number of years and

a is the amount on deposit at the end of the nth year.

Calculating Compound Interest

To solve this problem, let’s use variables principal and rate that we defined in snippets [5] and [7], and a for statement that performs the interest calculation for each of the 10 years the money remains on deposit. For each year, the loop displays a formatted string containing the year number and the amount on deposit at the end of that year:

In [15]: for year in range(1, 11):
    ...:     amount = principal * (1 + rate) ** year
    ...:     print(f'{year:>2}{amount:>10.2f}')
    ...:    
 1   1050.00
 2   1102.50
 3   1157.62
 4   1215.51
 5   1276.28
 6   1340.10
 7   1407.10
 8   1477.46
 9   1551.33
10   1628.89

The algebraic expression (1 + r)n from the requirements statement is written as

(1 + rate) ** year

where variable rate represents r and variable year represents n.

Formatting the Year and Amount on Deposit

The statement

print(f'{year:>2}{amount:>10.2f}')

uses an f-string with two placeholders to format the loop’s output.

The placeholder

{year:>2}

uses the format specifier >2 to indicate that year’s value should be right aligned (>) in a field of width 2—the field width specifies the number of character positions to use when displaying the value. For the single-digit year values 19, the format specifier >2 displays a space character followed by the value, thus right aligning the years in the first column. The following diagram shows the numbers 1 and 10 each formatted in a field width of 2:

A diagram shows the formatting of field width of 2.

You can left align values with <.

The format specifier 10.2f in the placeholder

{amount:>10.2f}

formats amount as a floating-point number (f) right aligned (>) in a field width of 10 with a decimal point and two digits to the right of the decimal point (.2). Formatting the amounts this way aligns their decimal points vertically, as is typical with monetary amounts. In the 10 character positions, the three rightmost characters are the number’s decimal point followed by the two digits to its right. The remaining seven character positions are the leading spaces and the digits to the decimal point’s left. In this example, all the dollar amounts have four digits to the left of the decimal point, so each number is formatted with three leading spaces. The following diagram shows the formatting for the value 1050.00:

A diagram shows the formatting of the value 1050.00.

3.12 break and continue Statements

The break and continue statements alter a loop’s flow of control. Executing a break statement in a while or for immediately exits that statement. In the following code, range produces the integer sequence 0–99, but the loop terminates when number is 10:

In [1]: for number in range(100):
   ...:     if number == 10:
   ...:         break
   ...:     print(number, end=' ')
   ...:    
0 1 2 3 4 5 6 7 8 9

In a script, execution would continue with the next statement after the for loop. The while and for statements each have an optional else clause that executes only if the loop terminates normally—that is, not as a result of a break.

Executing a continue statement in a while or for loop skips the remainder of the loop’s suite. In a while, the condition is then tested to determine whether the loop should continue executing. In a for, the loop processes the next item in the sequence (if any):

In [2]: for number in range(10):
   ...:     if number == 5:
   ...:         continue
   ...:     print(number, end=' ')
   ...:    
0 1 2 3 4 6 7 8 9

3.13 Boolean Operators and, or and not

The conditional operators >, <, >=, <=, == and != can be used to form simple conditions such as grade >= 60. To form more complex conditions that combine simple conditions, use the and, or and not Boolean operators.

Boolean Operator and

To ensure that two conditions are both True before executing a control statement’s suite, use the Boolean and operator to combine the conditions. The following code defines two variables, then tests a condition that’s True if and only if both simple conditions are True—if either (or both) of the simple conditions is False, the entire and expression is False:

In [1]: gender = 'Female'

In [2]: age = 70

In [3]: if gender == 'Female' and age >= 65:
   ...:     print('Senior female')
   ...:    
Senior female

The if statement has two simple conditions:

  • gender == 'Female' determines whether a person is a female and

  • age >= 65 determines whether that person is a senior citizen.

The simple condition to the left of the and operator evaluates first because == has higher precedence than and. If necessary, the simple condition to the right of and evaluates next, because >= has higher precedence than and. (We’ll discuss shortly why the right side of an and operator evaluates only if the left side is True.) The entire if statement condition is True if and only if both of the simple conditions are True. The combined condition can be made clearer by adding redundant parentheses

(gender == 'Female') and (age >= 65)

The table below summarizes the and operator by showing all four possible combinations of False and True values for expression1 and expression2—such tables are called truth tables:

expression1

expression2

expression1 and expression2

False

False

False

False

True

False

True

False

False

True

True

True

Boolean Operator or

Use the Boolean or operator to test whether one or both of two conditions are True. The following code tests a condition that’s True if either or both simple conditions are True—the entire condition is False only if both simple conditions are False:

In [4]:   semester_average = 83

In [5]:   final_exam = 95

In [6]: if semester_average >= 90 or final_exam >= 90:
   ...:       print('Student   gets an A')
   ...:    
Student gets an A

Snippet [6] also contains two simple conditions:

  • semester_average >= 90 determines whether a student’s average was an A (90 or above) during the semester, and

  • final_exam >= 90 determines whether a student’s final-exam grade was an A.

The truth table below summarizes the Boolean or operator. Operator and has higher precedence than or.

expression1

expression2

expression1 or expression2

False

False

False

False

True

True

True

False

True

True

True

True

Improving Performance with Short-Circuit Evaluation

Python stops evaluating an and expression as soon as it knows whether the entire condition is False. Similarly, Python stops evaluating an or expression as soon as it knows whether the entire condition is True. This is called short-circuit evaluation. So the condition

gender == 'Female' and age >= 65

stops evaluating immediately if gender is not equal to 'Female' because the entire expression must be False. If gender is equal to 'Female', execution continues, because the entire expression will be True if the age is greater than or equal to 65.

Similarly, the condition

semester_average >= 90 or final_exam >= 90

stops evaluating immediately if semester_average is greater than or equal to 90 because the entire expression must be True. If semester_average is less than 90, execution continues, because the expression could still be True if the final_exam is greater than or equal to 90.

In expressions that use and, make the condition that’s more likely to be False the leftmost condition. In or operator expressions, make the condition that’s more likely to be True the leftmost condition. These techniques can reduce a program’s execution time.

Boolean Operator not

The Boolean operator not “reverses” the meaning of a condition—True becomes False and False becomes True. This is a unary operator—it has only one operand. You place the not operator before a condition to choose a path of execution if the original condition (without the not operator) is False, such as in the following code:

In [7]: grade = 87

In [8]: if not grade == -1:
   ...:    print('The next grade is', grade)
   ...:   
The next grade is   87

Often, you can avoid using not by expressing the condition in a more “natural” or convenient manner. For example, the preceding if statement can also be written as follows:

In [9]: if grade != -1:
   ...:    print('The next grade is', grade)
   ...:   
The next grade is   87

The truth table below summarizes the not operator.

expression

not expression

False

True

True

False

The following table shows the precedence and grouping of the operators introduced so far, from top to bottom, in decreasing order of precedence.

Operators

Grouping

()

left to right

**

right to left

* / // %

left to right

+ -

left to right

< <= > >= == !=

left to right

not

left to right

and

left to right

or

left to right

3.14 Intro to Data Science: Measures of Central Tendency—Mean, Median and Mode

Here we continue our discussion of using statistics to analyze data with several additional descriptive statistics, including:

  • mean—the average value in a set of values.

  • median—the middle value when all the values are arranged in sorted order.

  • mode—the most frequently occurring value.

These are measures of central tendency—each is a way of producing a single value that represents a “central” value in a set of values, i.e., a value which is in some sense typical of the others.

Let’s calculate the mean, median and mode on a list of integers. The following session creates a list called grades, then uses the built-in sum and len functions to calculate the mean “by hand”—sum calculates the total of the grades (397) and len returns the number of grades (5):

In [1]: grades = [85, 93, 45, 89, 85]

In [2]: sum(grades) / len(grades)
Out[2]: 79.4

The previous chapter mentioned the descriptive statistics count and sum—implemented in Python as the built-in functions len and sum. Like functions min and max (introduced in the preceding chapter), sum and len are both examples of functional-style programming reductions—they reduce a collection of values to a single value—the sum of those values and the number of values, respectively. In Section 3.8’s class-average example, we could have deleted lines 10–15 of the script and replaced average in line 16 with snippet [2]’s calculation.

The Python Standard Library’s statistics module provides functions for calculating the mean, median and mode—these, too, are reductions. To use these capabilities, first import the statistics module:

In [3]: import statistics

Then, you can access the module’s functions with “statistics.” followed by the name of the function to call. The following calculates the grades list’s mean, median and mode, using the statistics module’s mean, median and mode functions:

In [4]: statistics.mean(grades)
Out[4]: 79.4

In [5]: statistics.median(grades)
Out[5]: 85

In [6]: statistics.mode(grades)
Out[6]: 85

Each function’s argument must be an iterable—in this case, the list grades. To confirm that the median and mode are correct, you can use the built-in sorted function to get a copy of grades with its values arranged in increasing order:

In [7]: sorted(grades)
Out[7]: [45, 85, 85, 89, 93]

The grades list has an odd number of values (5), so median returns the middle value (85). If the list’s number of values is even, median returns the average of the two middle values. Studying the sorted values, you can see that 85 is the mode because it occurs most frequently (twice). The mode function causes a StatisticsError for lists like

         [85, 93, 45, 89, 85, 93]

in which there are two or more “most frequent” values. Such a set of values is said to be bimodal. Here, both 85 and 93 occur twice.

3.15 Wrap-Up

In this chapter, we discussed Python’s control statements, including if, if... else, if... elif... else, while, for, break and continue. You saw that the for statement performs sequence-controlled iteration—it processes each item in an iterable, such as a range of integers, a string or a list. You used the built-in function range to generate sequences of integers from 0 up to, but not including, its argument, and to determine how many times a for statement iterates.

You used sentinel-controlled iteration with the while statement to create a loop that continues executing until a sentinel value is encountered. You used built-in function range’s two-argument version to generate sequences of integers from the first argument’s value up to, but not including, the second argument’s value. You also used the three-argument version in which the third argument indicated the step between integers in a range.

We introduced the Decimal type for precise monetary calculations and used it to calculate compound interest. You used f-strings and various format specifiers to create formatted output. We introduced the break and continue statements for altering the flow of control in loops. We discussed the Boolean operators and, or and not for creating conditions that combine simple conditions.

Finally, we continued our discussion of descriptive statistics by introducing measures of central tendency—mean, median and mode—and calculating them with functions from the Python Standard Library’s statistics module.

In the next chapter, you’ll create custom functions and use existing functions from Python’s math and random modules. We show several predefined functional-programming reductions and you’ll see additional functional-programming capabilities.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.118.126.11