I’m starting at 0, not 1, because
the indices of a
sequence
type
such as a
str
ing
or
list
begin at 0.
For example,
the first character in a
str
ing
is said to be character number 0.
0 1 2 3 4 5 6 7 8 9
The indented statements will be repeated over and over as long as it is still
true that
i < 10
.
Indent each indented statement with exactly
four
spaces.
0 1 2 3 4 5 6 7 8 9
The three vital statistics of a loop are
In a
while
loop,
the three vital statistics are on three separate lines.
In a
for
loop,
the three vital statistics are on the same line.
We therefore say that the
for
loop is more
localized.
range(10)
means the same thing as
range(0, 10)
and
range(0, 10, 1)
.
We can write the expression
range(10)
to the right of the keyword
in
because the value of this expression is an
iterable
object.
What is an
iterable
object?
For the time being,
we’re just going to define it as
“something you can write to the right of the keyword
in
“,
although I admit that this definition is circular.
A better definition might be
“something that, when properly stimulated,
gives you a sequence of values”.
The
for
loop and the keyword
in
provide that stimulation.
In the current program,
the sequence of values is the sequence of 10 consecutive
int
s
from 0 to 9 inclusive.
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 The value of i after the for loop is over is 9.
The built-in function
list
converts its argument into an actual
list,
just like the built-in function
int
converts its argument into an
int.
>>> range(0, 10) range(0, 10) Not very illuminating. >>> type(range(0, 10)) What type of thing is a range? <class 'range'> >>> len(range(0, 10)) We applied this function to a string. 10 >>> list(range(0, 10)) Convert the range into a list. [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] >>> list(range(10)) Let’s try it with one argument. [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] >>> list(range(0, 10, 2)) Let’s try it with three arguments. [0, 2, 4, 6, 8] >>> list(range(0, 10, .5)) Let’s try it with a fractional third argument. Traceback (most recent call last): File "<pyshell#3>", line 1, in <module> list(range(0, 10, .5)) TypeError: 'float' object cannot be interpreted as an integer
When we get to Iterators, we’ll be able to have a fractional step by making an iterable.
try: it = iter(range(10)) except TypeError as error: print("not iterable:", error) else: print("iterable")
iterable
Is a
str
ing
iterable?
If so,
that would be another piece of evidence that a
range
is similar to a
str
ing.
it = iter("hello")
8 pierogies feed 4 people or 2 Hungarians. 12 pierogies feed 6 people or 3 Hungarians. 16 pierogies feed 8 people or 4 Hungarians. 20 pierogies feed 10 people or 5 Hungarians. 24 pierogies feed 12 people or 6 Hungarians. 28 pierogies feed 14 people or 7 Hungarians. 32 pierogies feed 16 people or 8 Hungarians.
Pad each number with a leading blank, if necessary, to make it at least two characters wide.
print(f"{4 * h:2} pierogies feed {2 * h:2} people or {h} Hungarians.")
8 pierogies feed 4 people or 2 Hungarians. 12 pierogies feed 6 people or 3 Hungarians. 16 pierogies feed 8 people or 4 Hungarians. 20 pierogies feed 10 people or 5 Hungarians. 24 pierogies feed 12 people or 6 Hungarians. 28 pierogies feed 14 people or 7 Hungarians. 32 pierogies feed 16 people or 8 Hungarians.
We saw a triple-quoted string here.
+--------------+ | Albany 108 | | Montreal 328 | | Buffalo 388 | +--------------+ +--------------+ | Albany 98 | | Montreal 318 | | Buffalo 378 | +--------------+ +--------------+ | Albany 88 | | Montreal 308 | | Buffalo 368 | +--------------+ +--------------+ | Albany 78 | | Montreal 298 | | Buffalo 358 | +--------------+ +--------------+ | Albany 68 | | Montreal 288 | | Buffalo 348 | +--------------+ +--------------+ | Albany 58 | | Montreal 278 | | Buffalo 338 | +--------------+ +--------------+ | Albany 48 | | Montreal 268 | | Buffalo 328 | +--------------+
It’s more readable to create the big string outside of the loop.
Then plug the three numbers into the big string
by calling the
format
method
of the big string:
#A string containing 5 lines, each ending with a newline character. sign = """\ +--------------+ | Albany {:3} | | Montreal {:3} | | Buffalo {:3} | +--------------+ """ for a in range(108, 38, -10): print(sign.format(a, a + 220, a + 280))
King James I of England was the same person as King James VI of Scotland. Similarly, King James II of England was the same person as King James VII of Scotland. And there almost was a King James III of England, who was the same person as King James VIII of Scotland. Get the pattern, like Albany and Montreal? Can you turn it into a Python program?
The letter
A
comes before the letter
B
in alphabetical order because the
ASCII
(vs.
EBCDIC)
code number of
A
(decimal 65)
comes before the code number of
B
(decimal 66).
We can extend this alphabetical order to all the other characters.
For example,
the digit
0
comes before the digit
1
in alphabetical order because the code number of the character
0
(decimal 48)
comes before the code number of the character
1
(decimal 49),
and the comma
,
comes before the period
.
in alphabetical order because the code number of the character
,
(decimal 44)
comes before the code number of the character
.
(decimal 46).
decimal octal hex binary (base 10) (base 8) (base 16) (base 2) 32 40 20 00100000 ! 33 41 21 00100001 " 34 42 22 00100010 # 35 43 23 00100011 $ 36 44 24 00100100 % 37 45 25 00100101 & 38 46 26 00100110 ' 39 47 27 00100111 ( 40 50 28 00101000 ) 41 51 29 00101001 * 42 52 2A 00101010 + 43 53 2B 00101011 , 44 54 2C 00101100 - 45 55 2D 00101101 . 46 56 2E 00101110 / 47 57 2F 00101111 0 48 60 30 00110000 1 49 61 31 00110001 2 50 62 32 00110010 3 51 63 33 00110011 4 52 64 34 00110100 5 53 65 35 00110101 6 54 66 36 00110110 7 55 67 37 00110111 8 56 70 38 00111000 9 57 71 39 00111001 : 58 72 3A 00111010 ; 59 73 3B 00111011 < 60 74 3C 00111100 = 61 75 3D 00111101 > 62 76 3E 00111110 ? 63 77 3F 00111111 @ 64 100 40 01000000 A 65 101 41 01000001 B 66 102 42 01000010 C 67 103 43 01000011 D 68 104 44 01000100 E 69 105 45 01000101 F 70 106 46 01000110 G 71 107 47 01000111 H 72 110 48 01001000 I 73 111 49 01001001 J 74 112 4A 01001010 K 75 113 4B 01001011 L 76 114 4C 01001100 M 77 115 4D 01001101 N 78 116 4E 01001110 O 79 117 4F 01001111 P 80 120 50 01010000 Q 81 121 51 01010001 R 82 122 52 01010010 S 83 123 53 01010011 T 84 124 54 01010100 U 85 125 55 01010101 V 86 126 56 01010110 W 87 127 57 01010111 X 88 130 58 01011000 Y 89 131 59 01011001 Z 90 132 5A 01011010 [ 91 133 5B 01011011 \ 92 134 5C 01011100 ] 93 135 5D 01011101 ^ 94 136 5E 01011110 _ 95 137 5F 01011111 ` 96 140 60 01100000 a 97 141 61 01100001 b 98 142 62 01100010 c 99 143 63 01100011 d 100 144 64 01100100 e 101 145 65 01100101 f 102 146 66 01100110 g 103 147 67 01100111 h 104 150 68 01101000 i 105 151 69 01101001 j 106 152 6A 01101010 k 107 153 6B 01101011 l 108 154 6C 01101100 m 109 155 6D 01101101 n 110 156 6E 01101110 o 111 157 6F 01101111 p 112 160 70 01110000 q 113 161 71 01110001 r 114 162 72 01110010 s 115 163 73 01110011 t 116 164 74 01110100 u 117 165 75 01110101 v 118 166 76 01110110 w 119 167 77 01110111 x 120 170 78 01111000 y 121 171 79 01111001 z 122 172 7A 01111010 { 123 173 7B 01111011 | 124 174 7C 01111100 } 125 175 7D 01111101 ~ 126 176 7E 01111110
IDLE
can’t display
emojis.
We therefore print the emojis in the terminal window,
not in
IDLE,
to avoid the error
UnicodeEncodeError:
'UCS-2' codec can't encode characters in position 6-6:
Non-BMP character not supported in Tk
.
The code number of the character
😀
is 128,512.
Written in hexadecimal, this number is
1F600
.
Here is how I used
IDLE
to convert from decimal to hexadecimal and back again.
>>> f"{128512:X}" '1F600' >>> 0x1F600 128512
""" Print the smiley face emojis, one per line. """ import sys print(" dec hex") for i in range(0x1F600, 0x1F650): #or for i in range(128_512, 128_592): print(f"{i:6} {i:05X} {i:c}") sys.exit(0)
python3 myprog.py dec hex 128512 1F600 😀 128513 1F601 😁 128514 1F602 😂 128515 1F603 😃 128516 1F604 😄 etc. 128587 1F64B 🙋 128588 1F64C 🙌 128589 1F64D 🙍 128590 1F64E 🙎 128591 1F64F 🙏
See also the
beer.py
that was installed when you installed Python.
find / -type f -name beer.py 2> /dev/null /Library/Frameworks/Python.framework/Versions/3.7/share/doc/python3.7/examples/Tools/demo/beer.py
cd C:\ dir /b /s beer.py C:\Users\Myname\AppData\Local\Programs\Python\Python37-32\Tools\demo\beer.py
100 bottles of beer on the wall, 100 bottles of beer on the wall-- If one of those bottles should happen to fall, 99 bottles of beer on the wall. 99 bottles of beer on the wall, 99 bottles of beer on the wall-- If one of those bottles should happen to fall, 98 bottles of beer on the wall. etc. 2 bottles of beer on the wall, 2 bottles of beer on the wall-- If one of those bottles should happen to fall, 1 bottles of beer on the wall. 1 bottles of beer on the wall, 1 bottles of beer on the wall-- If one of those bottles should happen to fall, 0 bottles of beer on the wall.
Call
print
only once per iteration:
#This format string contains four lines of text, #each ending with the newline character. verse = """\ {} bottles of beer on the wall, {} bottles of beer--- If one of those bottles should happen to fall, {} bottles of beer on the wall. """ for b in range(100, 0, -1): print(verse.format(b, b, b - 1)) #time.sleep(3)
Count down and make a blastoff.
fontsize.py
outputs the web page
fontsize.html
.
See
pangrams.
<HTML> <BODY> <H1>Stylesheet</H1> <P STYLE = "font-size: 1pt;"> 1 point <BR> Pack my box with five dozen liquor jugs. </P> <P STYLE = "font-size: 2pt;"> 2 point <BR> Pack my box with five dozen liquor jugs. </P> <P STYLE = "font-size: 3pt;"> 3 point <BR> Pack my box with five dozen liquor jugs. </P> <P STYLE = "font-size: 4pt;"> 4 point <BR> Pack my box with five dozen liquor jugs. </P> <P STYLE = "font-size: 5pt;"> 5 point <BR> Pack my box with five dozen liquor jugs. </P> <P STYLE = "font-size: 6pt;"> 6 point <BR> Pack my box with five dozen liquor jugs. </P> <P STYLE = "font-size: 7pt;"> 7 point <BR> Pack my box with five dozen liquor jugs. </P> <P STYLE = "font-size: 8pt;"> 8 point <BR> Pack my box with five dozen liquor jugs. </P> <P STYLE = "font-size: 9pt;"> 9 point <BR> Pack my box with five dozen liquor jugs. </P> <P STYLE = "font-size: 10pt;"> 10 point <BR> Pack my box with five dozen liquor jugs. </P> <P STYLE = "font-size: 11pt;"> 11 point <BR> Pack my box with five dozen liquor jugs. </P> <P STYLE = "font-size: 12pt;"> 12 point <BR> Pack my box with five dozen liquor jugs. </P> </BODY> </HTML>
To render the output in HTML,
save the standard output of
fontsize.py
in a new file named
fontsize.html
.
On MacOS,
python3 fontsize.py > fontsize.html ls -l fontsize.html
On Microsoft Windows,
fontsize.py > fontsize.html dir fontsize.html
Then open your new
fontsize.html
file with a web browser.
On macOS, control-click on
fontsize.html
and select
Open With →
Google Chrome.app
It will look like this:
fontsize.html
We could also have used the
format
method:
#This format string contains six lines of text. #The last line is empty (i.e., consists only of one newline character). paragraph = """\ <P STYLE = "font-size: {}pt;"> {} point <BR> Pack my box with five dozen liquor jugs. </P> """ for point in range(1, 13): print(paragraph.format(points, points))
We saw nested
while
loops
here.
See also the function
intertools.product
.
Lucy in the sky with diamonds Lucy in the sky with diamonds Lucy in the sky with diamonds Aaaaaaaaaaaaaaaaaaaaaaaaaaaaah Lucy in the sky with diamonds Lucy in the sky with diamonds Lucy in the sky with diamonds Aaaaaaaaaaaaaaaaaaaaaaaaaaaaah Lucy in the sky with diamonds Lucy in the sky with diamonds Lucy in the sky with diamonds Aaaaaaaaaaaaaaaaaaaaaaaaaaaaah
for outer in range(3): print(f"chorus (outer = {outer})") for inner in range(3): print(f"Lucy in the sky with diamonds (inner = {inner})") print(f'A{28 * "a"}h') print()
chorus (outer = 0) Lucy in the sky with diamonds (inner = 0) Lucy in the sky with diamonds (inner = 1) Lucy in the sky with diamonds (inner = 2) Aaaaaaaaaaaaaaaaaaaaaaaaaaaaah chorus (outer = 1) Lucy in the sky with diamonds (inner = 0) Lucy in the sky with diamonds (inner = 1) Lucy in the sky with diamonds (inner = 2) Aaaaaaaaaaaaaaaaaaaaaaaaaaaaah chorus (outer = 2) Lucy in the sky with diamonds (inner = 0) Lucy in the sky with diamonds (inner = 1) Lucy in the sky with diamonds (inner = 2) Aaaaaaaaaaaaaaaaaaaaaaaaaaaaah
By the way, we can also produce the original output using string multiplication and string addition:
import sys moan = "A" + 28 * "a" + "h" paragraph = 3 * "Lucy in the sky with diamonds\n" + moan + "\n\n" print(3 * paragraph, end = "") sys.exit(0)
The
end
keyword
argument
of
print
keeps all the
X
’s
on the same line of output.
But every line of output should end with a newline character,
so that’s why this program also makes a no-argument call to
print
.
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Let the user input four numbers to design a sheet of graph paper. For simplicity, let the right and bottom edges remain ragged. Here are two examples:
How many rows of boxes (e.g., 3)? 3 How many columns of boxes (e.g., 4)? 4 How many rows of spaces in each box (e.g., 1)? 1 How many columns of spaces in each box (e.g., 3)? 4 +----+----+----+---- | | | | +----+----+----+---- | | | | +----+----+----+---- | | | |
How many rows of boxes (e.g., 3)? 2 How many columns of boxes (e.g., 4)? 4 How many rows of spaces in each box (e.g., 1)? 3 How many columns of spaces in each box (e.g., 3)? 8 +--------+--------+--------+-------- | | | | | | | | | | | | +--------+--------+--------+-------- | | | | | | | | | | | |
Extra credit: close the right and bottom edges.
How many rows of boxes (e.g., 3)? 2 How many columns of boxes (e.g., 4)? 4 How many rows of spaces in each box (e.g., 1)? 3 How many columns of spaces in each box (e.g., 3)? 8 +--------+--------+--------+--------+ | | | | | | | | | | | | | | | +--------+--------+--------+--------+ | | | | | | | | | | | | | | | +--------+--------+--------+--------+
If the graph paper problem is too hard, start with a script that asks only two questions and outputs only the first line of the graph paper:
How many columns of boxes (e.g., 4)? 4 How many columns of spaces in each box (e.g., 3)? 4 +----+----+----+----
i = 2 while i < 10: print(i) i += 2 print("Who do we appreciate?") print() #Skip a line. for i in range(2, 10, 2): print(i) print("Who do we appreciate?")
2 4 6 8 Who do we appreciate? 2 4 6 8 Who do we appreciate?
List the presidential election years: 1788, 1792, 1796, …, 2012, 2016, 2020.
The
range(1, 100, 2)
contains the fifty integers 1, 3, 5, 7, 9, …, 99.
""" Estimate the value of pi using the formula pi = 4/1 - 4/3 + 4/5 - 4/7 + 4/9 - 4/11 + 4/13 + ... """ import sys import math pi = 0 sign = 1 for denominator in range(1, 100, 2): pi += sign / denominator #means pi = pi + sign / denominator sign = -sign pi *= 4 #means pi = pi * 4 print(f"estimated pi = {pi}") print(f"actual pi = {math.pi}") print(f"error = {abs(pi - math.pi)}") sys.exit(0)
estimated pi = 3.121594652591011 actual pi = 3.141592653589793 error = 0.01999800099878213
Get more accuracy by changing 100 to 1000 (or to 10000):
estimated pi = 3.139592655589785 actual pi = 3.141592653589793 error = 0.001999998000008052
How many times do we have to loop until we get close to the value of π?
""" Estimate the value of pi using the formula pi = 4/1 - 4/3 + 4/5 - 4/7 + 4/9 - 4/11 + 4/13 + ... """ import sys import math import itertools pi = 0 sign = 1 for denominator in itertools.count(1, 2): #Loop forever: 1, 3, 5, 7, 9, ... if abs(4 * pi - math.pi) < .001: break pi += sign / denominator #means pi = pi + sign / denominator sign = -sign pi *= 4 #means pi = pi * 4 print("denominator = ", denominator) print(f"estimated pi = {pi}") print(f"actual pi = {math.pi}") print(f"error = {abs(pi - math.pi)}") print(f"It took {(denominator - 1) // 2:,} additions and subtractions to get this close.") sys.exit(0)
estimated pi = 3.140592653839794 actual pi = 3.141592653589793 error = 0.000999999749998981 It took 1,000 additions and subtractions to get this close.