1. static.realpython.com/python-basics-sample-chapters.pdf, page 96
4.6. Working With Strings and Numbers
Try converting the string "12.0" to an integer:
>>> int("12.0")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: invalid literal for int() with base 10: '12.0'
Even though the extra 0 after the decimal place doesn’t add any value
to the number, Python won’t change 12.0 into 12 because it would result in a loss of precision.
Let’s revisit the program from the beginning of this section and see
how to fix it. Here’s the code again:
num = input("Enter a number to be doubled: ")
doubled_num = num * 2
print(doubled_num)
The issue is on the line doubled_num = num * 2 because num is a string
and 2 is an integer.
You can fix the problem by passing num to either int() or float(). Since
the prompts asks the user to input a number, and not specifically an
integer, let’s convert num to a floating-point number:
num = input("Enter a number to be doubled: ")
doubled_num = float(num) * 2
print(doubled_num)
Now when you run this program and input 2, you get 4.0 as expected.
Try it out!
Converting Numbers to Strings
Sometimes you need to convert a number to a string. You might do
this, for example, if you need to build a string from some preexisting
variables that are assigned to numeric values.
92
4.6. Working With Strings and Numbers
As you’ve already seen, concatenating a number with a string produces a TypeError:
>>> num_pancakes = 10
>>> "I am going to eat " + num_pancakes + " pancakes."
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can only concatenate str (not "int") to str
Since num_pancakes is a number, Python can’t concatenate it with the
string "I'm going to eat". To build the string, you need to convert
num_pancakes to a string using str():
>>> num_pancakes = 10
>>> "I am going to eat " + str(num_pancakes) + " pancakes."
'I am going to eat 10 pancakes.'
You can also call str() on a number literal:
>>> "I am going to eat " + str(10) + " pancakes."
'I am going to eat 10 pancakes.'
str() can even handle arithmetic expressions:
>>> total_pancakes = 10
>>> pancakes_eaten = 5
>>> "Only " + str(total_pancakes - pancakes_eaten) + " pancakes left."
'Only 5 pancakes left.'
In the next section, you’ll learn how to format strings neatly to display
values in a nice, readable manner. Before you move on, though, check
your understanding with the following review exercises.
93
4.7. Streamline Your Print Statements
Review Exercises
You can nd the solutions to these exercises and many other bonus
resources online at realpython.com/python-basics/resources
1. Create a string containing an integer, then convert that string into
an actual integer object using int(). Test that your new object is
a number by multiplying it by another number and displaying the
result.
2. Repeat the previous exercise, but use a floating-point number and
float().
3. Create a string object and an integer object, then display them side
by side with a single print statement using str().
4. Write a program that uses input() twice to get two numbers from
the user, multiplies the numbers together, and displays the result.
If the user enters 2 and 4, then your program should print the
following text:
The product of 2 and 4 is 8.0.
4.7 Streamline Your Print Statements
Suppose you have a string, name = "Zaphod", and two integers, heads
= 2 and arms = 3. You want to display them in the string "Zaphod has
2 heads and 3 arms". This is called string interpolation, which is
just a fancy way of saying that you want to insert some variables into
specific locations in a string.
One way to do this is with string concatenation:
>>> name + " has " + str(heads) + " heads and " + str(arms) + " arms"
'Zaphod has 2 heads and 3 arms'
This code isn’t the prettiest, and keeping track of what goes inside or
outside the quotes can be tough. Fortunately, there’s another way of
interpolating strings: formatted string literals, more commonly
94
4.7. Streamline Your Print Statements
known as f-strings.
The easiest way to understand f-strings is to see them in action. Here’s
what the above string looks like when written as an f-string:
>>> f"{name} has {heads} heads and {arms} arms"
'Zaphod has 2 heads and 3 arms'
There are two important things to notice about the above example:
1. The string literal starts with the letter f before the opening quotation mark.
2. Variable names surrounded by curly braces ({}) are replaced by
their corresponding values without using str().
You can also insert Python expressions between the curly braces. The
expressions are replaced with their result in the string:
>>> n = 3
>>> m = 4
>>> f"{n} times {m} is {n*m}"
'3 times 4 is 12'
It’s a good idea to keep any expressions used in an f-string as simple
as possible. Packing a bunch of complicated expressions into a string
literal can result in code that is difficult to read and difficult to maintain.
f-strings are available only in Python version 3.6 and above. In earlier versions of Python, you can use .format() to get the same results.
Returning to the Zaphod example, you can use .format() to format the
string like this:
>>> "{} has {} heads and {} arms".format(name, heads, arms)
'Zaphod has 2 heads and 3 arms'
f-strings are shorter and sometimes more readable than using .format(). You’ll see f-strings used throughout this book.
95
2. static.realpython.com/python-basics-sample-chapters.pdf, page 94
4.6. Working With Strings and Numbers
Type "12" * "3" in the interactive window and press Enter :
>>> "12" * "3"
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can't multiply sequence by non-int of type 'str'
Python raises a TypeError and tells you that you can’t multiply a sequence by a non-integer.
Note
A sequence is any Python object that supports accessing elements by index. Strings are sequences. You’ll learn about other
sequence types in chapter 9.
When you use the * operator with a string, Python always expects an
integer on the other side of the operator.
What do you think happens when you try to add a string and a number?
>>> "3" + 3
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can only concatenate str (not "int") to str
Python throws a TypeError because it expects the objects on both sides
of the + operator to be of the same type.
If an object on either side of + is a string, then Python tries to perform
string concatenation. It will only perform addition if both objects are
numbers. So, to add "3" + 3 and get 6, you must first convert the string
"3" to a number.
90
4.6. Working With Strings and Numbers
Converting Strings to Numbers
The TypeError examples in the previous section highlight a common
problem when applying user input to an operation that requires a
number and not a string: type mismatches.
Let’s look at an example. Save and run the following program:
num = input("Enter a number to be doubled: ")
doubled_num = num * 2
print(doubled_num)
If you entered the number 2 at the prompt, then you would expect the
output to be 4. But in this case, you would get 22. Remember, input()
always returns a string, so if you input 2, then num is assigned the string
"2", not the integer 2. Therefore, the expression num * 2 returns the
string "2" concatenated with itself, which is "22".
To perform arithmetic on numbers contained in a string, you must
first convert them from a string type to a number type. There are two
functions that you can use to do this: int() and float().
int() stands for integer and converts objects into whole numbers,
whereas float() stands for oating-point number and converts objects into numbers with decimal points. Here’s what using each one
looks like in the interactive window:
>>> int("12")
12
>>> float("12")
12.0
Notice how float() adds a decimal point to the number. Floatingpoint numbers always have at least one decimal place of precision. For
this reason, you can’t change a string that looks like a floating-point
number into an integer because you would lose everything after the
decimal point.
91
4.6. Working With Strings and Numbers
Try converting the string "12.0" to an integer:
>>> int("12.0")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: invalid literal for int() with base 10: '12.0'
Even though the extra 0 after the decimal place doesn’t add any value
to the number, Python won’t change 12.0 into 12 because it would result in a loss of precision.
Let’s revisit the program from the beginning of this section and see
how to fix it. Here’s the code again:
num = input("Enter a number to be doubled: ")
doubled_num = num * 2
print(doubled_num)
The issue is on the line doubled_num = num * 2 because num is a string
and 2 is an integer.
You can fix the problem by passing num to either int() or float(). Since
the prompts asks the user to input a number, and not specifically an
integer, let’s convert num to a floating-point number:
num = input("Enter a number to be doubled: ")
doubled_num = float(num) * 2
print(doubled_num)
Now when you run this program and input 2, you get 4.0 as expected.
Try it out!
Converting Numbers to Strings
Sometimes you need to convert a number to a string. You might do
this, for example, if you need to build a string from some preexisting
variables that are assigned to numeric values.
92
4.6. Working With Strings and Numbers
As you’ve already seen, concatenating a number with a string produces a TypeError:
>>> num_pancakes = 10
>>> "I am going to eat " + num_pancakes + " pancakes."
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can only concatenate str (not "int") to str
Since num_pancakes is a number, Python can’t concatenate it with the
string "I'm going to eat". To build the string, you need to convert
num_pancakes to a string using str():
>>> num_pancakes = 10
>>> "I am going to eat " + str(num_pancakes) + " pancakes."
'I am going to eat 10 pancakes.'
You can also call str() on a number literal:
>>> "I am going to eat " + str(10) + " pancakes."
'I am going to eat 10 pancakes.'
str() can even handle arithmetic expressions:
>>> total_pancakes = 10
>>> pancakes_eaten = 5
>>> "Only " + str(total_pancakes - pancakes_eaten) + " pancakes left."
'Only 5 pancakes left.'
In the next section, you’ll learn how to format strings neatly to display
values in a nice, readable manner. Before you move on, though, check
your understanding with the following review exercises.
93
3. edu.anarcho-copy.org/Programming%20Languages/Python/Automate%20the%20Boring%20Stuff%20with%20Python.pdf, page 490
folders, 368–369
getting message content,
372–373
logging into server, 368
overview, 366–367
raw messages, 373–375
gmail_search() method, 372
IMAP, 366
marking message as read, 372–373
searching, 368–371
sending
connecting to SMTP server,
363–364
disconnecting from server, 366
logging into server, 364–365
overview, 362
reminder, 376–380
sending “hello” message, 364
sending message, 365
TLS encryption, 364
SMTP, 362
emboss attribute, 311
encryption, of PDF files, 302–303
endswith() method, 131
epoch timestamps, 336, 341, 346
equal to (==) operator, 33, 34
ERROR level, 224
errors
crashes and, 14
help for, 8–9
escape characters, 124–125
evaluation, defined, 14
Excel spreadsheets
application support, 265–266
charts in, 288–290
column width, 285–286
converting between column letters
and numbers, 270
creating documents, 277
creating worksheets, 278
deleting worksheets, 278
font styles, 282–284
formulas in, 284–285
freezing panes, 287–288
getting cell values, 268–269
getting rows and columns, 270–272
getting worksheet names, 268
merging and unmerging cells,
286–287
opening documents, 267
openpyxl module, 266
overview, 266–267
reading files
overview, 272–273
populating data structure,
274–275
reading data, 273–274
writing results to file, 275–276
and reminder emails project,
376–380
row height, 285–286
saving workbooks, 277
updating, 279–281
overview, 279–280
setup, 280
workbooks vs., 266
writing values to cells, 278–279
Exception objects, 217
exceptions
assertions and, 219–221
getting traceback as string, 217–218
handling, 72–74
raising, 216–217
execution, program
defined, 31
overview, 38
pausing until specific time, 344
terminating program with
sys.exit(), 58
exists() function, 180
exit codes, 353–354
expand keyword, 398
exponent (**) operator, 15
expressions
conditions and, 37
in interactive shell, 14–16
expunge() method, 375
extensions, file, 173
extractall() method, 205
extracting ZIP files, 205
extract() method, 205
F
FailSafeException exception, 434
“falsey” values, 53
fetch() method, 371, 372–373
file editor, 21
file management
absolute vs. relative paths, 175–176
backslash vs. forward slash, 174–175
compressed files
backing up to, 209–212
creating ZIP files, 205–206
Index 465
file management (continued)
compressed files (continued)
extracting ZIP files, 205
overview, 203–204
reading ZIP files, 204
creating directories, 176
current working directory, 175
multiclipboard project, 191–193
opening files, 181–182
os.path module
absolute paths in, 177–179
file sizes, 179–180
folder contents, 179–180
overview, 177
path validity, 180
relative paths in, 177–179
overview, 173–174
paths, 173–174
plaintext vs. binary files, 180–181
reading files, 182–183
renaming files, date styles, 206–209
saving variables with pformat()
function, 185–186
send2trash module, 201–202
shelve module, 184–185
shutil module
copying files/folders, 198–199
deleting files/folders, 200–201
moving files/folders, 199–200
renaming files/folders, 199–200
walking directory trees, 202–203
writing files, 183–184
filenames, defined, 173
File objects, 182
findall() method, 157–158
find_element_by_* methods, 257–258
find_elements_by_* methods, 257–258
Firefox, developer tools in, 243
FLAGGED search key, 370
flipping images, 398–399
float() function, 25–28
floating-point numbers
integer equivalence, 27
overview, 17
rounding, 338
flow control
binary operators, 35–36
blocks of code, 37–38
Boolean values and, 32–33
break statements, 49–50
comparison operators, 33–35
conditions, 37
466 Index
continue statements, 50–53
elif statements, 40–45
else statements, 39–40
if statements, 38–39
overview, 31–32
using binary and comparison
operators together, 36–37
while loops, 45–49
folders
absolute vs. relative paths, 175–176
backing up to ZIP file, 209–212
creating new ZIP file, 211
figuring out ZIP filename,
210–211
walking directory tree, 211–212
backslash vs. forward slash, 174–175
copying, 198–199
creating, 176
current working directory, 175
defined, 173–174
deleting permanently, 200–201
deleting using send2trash module,
201–202
moving, 199–200
os.path module
absolute paths in, 177–179
file sizes, 179–180
folder contents, 179–180
overview, 177
path validity, 180
relative paths in, 177–179
renaming, 199–200
walking directory trees, 202–203
Font objects, 282–283
font styles, in Excel spreadsheets,
282–284
for loops
overview, 53–56
using dictionary items in, 108
using lists with, 86
format attribute, 392
format_description attribute, 392
formData list, 434
form filler project, 430–437
overview, 430–431
radio buttons, 435–436
select lists, 435–436
setting up coordinates, 432–434
steps in process, 431
submitting form, 436–437
typing data, 434–435
4. edu.anarcho-copy.org/Programming%20Languages/Python/Automate%20the%20Boring%20Stuff%20with%20Python.pdf, page 500
read() method, 182
rectangle() method, 407
Reddit, 9
Reference objects, 289
references
overview, 97–99
passing, 100
refresh() method, 261
Regex objects
creating, 150
matching, 151
regular expressions
beginning of string matches,
159–160
case sensitivity, 163
character classes, 158–159
creating Regex objects, 150–151
defined, 147–148
end of string matches, 159–160
extracting phone numbers and
emails addresses, 165–169
findall() method, 157–158
finding text without, 148–150
greedy matching, 156–157
grouping
matching specific
repetitions, 156
one or more matches, 155–156
optional matching, 154–155
using parentheses, 152–153
using pipe character in, 153–154
zero or more matches, 155
HTML and, 243
matching with, 151–152
multiple arguments for compile()
function, 164–165
nongreedy matching, 157
patterns for, 150
spreading over multiple lines, 164
substituting strings using, 163–164
symbol reference, 162
wildcard character, 160–162
relative paths, 175–179
relpath() function, 177, 178
remainder/modulus (%) operator, 15, 88
remove() method, 90–91
remove_sheet() method, 278
renaming files/folders, 199–200
date styles, 206–209
creating regex for dates, 206
identifying dates in filenames,
207–208
overview, 206
renaming files, 209
replication
of lists, 83
string, 18
requests module
downloading files, 239–240
downloading pages, 237–238
resolution of computer screen, 416
Response objects, 237–238
return values, function, 63–65
reverse keyword, 91
RGBA values, 388–389
RGB color model, 389
rightClick() function, 420, 430
rjust() method, 133–134, 419
rmdir() function, 200
rmtree() function, 200
rotateClockwise() method, 300
rotateCounterClockwise() method, 300
rotating images, 398–399
rounding numbers, 338
rows, in Excel spreadsheets
setting height and width of, 285–286
slicing Worksheet objects to get
Cell objects in, 270–272
rstrip() method, 134–135
rtl attribute, 311
Run objects, 310, 311–312
running programs
on Linux, 445
on OS X, 445
overview, 443
on Windows, 444–445
shebang line, 443–444
S
\S character class, 158
\s character class, 158
%S directive, 344
Safari, developer tools in, 243
save() method, 391
scope
global, 70–71
local, 67–70
screenshot() function, 423, 430
screenshots
analyzing, 424
getting, 423
scripts
running from Python program, 355
running outside of IDLE, 136
Index 475
scroll() function, 422, 423, 430
scrolling mouse, 422–423
searching
email, 368–371
the Web, 248–251
finding results, 249–250
getting command line
arguments, 249
opening web browser for
results, 250–251
overview, 248
requesting search page, 249
search() method, 151
SEEN search key, 370
see program, 355
select_folder() method, 369
select lists, 435–436
select() method, bs4 module, 246–247
selectors, CSS, 246–247, 258
selenium module
clicking buttons, 261
finding elements, 257–259
following links, 259
installing, 256
sending special keystrokes, 260–261
submitting forms, 259–260
using Firefox with, 256–257
send2trash module, 201–202
sending reminder emails, 376–379
finding unpaid members, 378
opening Excel file, 376–377
overview, 376
sending emails, 378–379
send_keys() method, 259–260
sendmail() method, 365, 379
sequence numbers, 373
sequences, 86
setdefault() method, 110–111
shadow attribute, 311
shebang line, 443–444
shelve module, 184–185
Short Message Service (SMS)
sending messages, 381–382
Twilio service, 380
shutil module
deleting files/folders, 200–201
moving files/folders, 199–200
renaming files/folders, 199–200
SID (string ID), 382
Simple Mail Transfer Protocol. See
SMTP (Simple Mail
Transfer Protocol)
476 Index
SINCE search key, 369
single quote ('), 124
single-threaded programs, 347
size() function, 416
sleep() function, 337–338, 344, 346, 355
slices
getting sublists with, 82–83
for strings, 126–127
small_caps attribute, 311
SMALLER search key, 370
SMS (Short Message Service)
sending messages, 381–382
Twilio service, 380
SMTP (Simple Mail Transfer Protocol)
connecting to server, 363–364
defined, 362
disconnecting from server, 366
logging into server, 364–365
sending “hello” message, 364
sending message, 365
TLS encryption, 364
SMTP objects, 363–364
sort() method, 91–92
sound files, playing, 357–358
source code, defined, 3
split() method, 131–133, 178, 320
spreadsheets. See Excel spreadsheets
square brackets [], 80
Stack Overflow, 9
standard library, 57
star (*), 161, 162
using with wildcard character, 161
zero or more matches with, 155
start() method, 348, 349, 351
start program, 355
startswith() method, 131
starttls() method, 364, 379
step argument, 56
stopwatch project, 338–340
overview, 338–339
set up, 339
tracking lap times, 339–340
strftime() function, 344–345, 346
str() function, 25–28, 97, 419
strike attribute, 311
string ID (SID), 382
strings
center() method, 133–134
concatenation, 17–18
converting datetime objects to,
344–345
converting to datetime objects, 345
5. static.realpython.com/python-basics-sample-chapters.pdf, page 69
4.1. What Is a String?
Note
Not every string is a string literal. Sometimes strings are input
by a user or read from a file. Since they’re not typed out with
quotation marks in your code, they’re not string literals.
The quotes surrounding a string are called delimiters because they
tell Python where a string begins and where it ends. When one type of
quotes is used as the delimiter, the other type can be used inside the
string:
string3 = "We're #1!"
string4 = 'I said, "Put it over by the llama."'
After Python reads the first delimiter, it considers all the characters
after it part of the string until it reaches a second matching delimiter.
This is why you can use a single quote in a string delimited by double
quotes, and vice versa.
If you try to use double quotes inside a string delimited by double
quotes, you’ll get an error:
>>> text = "She said, "What time is it?""
File "<stdin>", line 1
text = "She said, "What time is it?""
^
SyntaxError: invalid syntax
Python throws a SyntaxError because it thinks the string ends after the
second ", and it doesn’t know how to interpret the rest of the line. If
you need to include a quotation mark that matches the delimiter inside a string, then you can escape the character using a backslash:
>>> text = "She said, \"What time is it?\""
>>> print(text)
She said, "What time is it?"
65
4.1. What Is a String?
Note
When you work on a project, it’s a good idea to use only single
quotes or only double quotes to delimit every string.
Keep in mind that there really isn’t a right or wrong choice! The
goal is to be consistent because consistency helps make your
code easier to read and understand.
Strings can contain any valid Unicode character. For example, the
string "We're #1!" contains the pound sign (#) and "1234" contains numbers. "×Pýŧħøŋ×" is also a valid Python string!
Determine the Length of a String
The number of characters contained in a string, including spaces, is
called the length of the string. For example, the string "abc" has a
length of 3, and the string "Don't Panic" has a length of 11.
Python has a built-in len() function that you can use to determine the
length of a string. To see how it works, type the following into IDLE’s
interactive window:
>>> len("abc")
3
You can also use len() to get the length of a string that’s assigned to a
variable:
>>> letters = "abc"
>>> len(letters)
3
First, you assign the string "abc" to the variable letters. Then you use
len() to get the length of letters, which is 3.
66
4.1. What Is a String?
Multiline Strings
The PEP 8 style guide recommends that each line of Python code contain no more than seventy-nine characters—including spaces.
Note
PEP 8’s seventy-nine-character line length is a recommendation, not a rule. Some Python programmers prefer a slightly
longer line length.
In this book, we’ll strictly follow PEP 8’s recommended line
length.
Whether you follow PEP 8 or choose a longer line length, sometimes
you’ll need to create string literals with more characters than your chosen limit.
To deal with long strings, you can break them up across multiple lines
into multiline strings. For example, suppose you need to fit the
following text into a string literal:
This planet has—or rather had—a problem, which was
this: most of the people living on it were unhappy for
pretty much of the time. Many solutions were suggested
for this problem, but most of these were largely concerned with the movements of small green pieces of
paper, which is odd because on the whole it wasn’t the
small green pieces of paper that were unhappy.
— Douglas Adams, The Hitchhiker’s Guide to the Galaxy
This paragraph contains far more than seventy-nine characters, so
any line of code containing the paragraph as a string literal violates
PEP 8. So, what do you do?
There are a couple of ways to tackle this. One way is to break the string
up across multiple lines and put a backslash (\) at the end of all but the
67
4.1. What Is a String?
last line. To be PEP 8 compliant, the total length of the line, including
the backslashes, must be seventy-nine characters or fewer.
Here’s how you could write the paragraph as a multiline string using
the backslash method:
paragraph = "This planet has—or rather had—a problem, which was \
this: most of the people living on it were unhappy for pretty much \
of the time. Many solutions were suggested for this problem, but \
most of these were largely concerned with the movements of small \
green pieces of paper, which is odd because on the whole it wasn't \
the small green pieces of paper that were unhappy."
Notice that you don’t have to close each line with a quotation mark.
Normally, Python would get to the end of the first line and complain
that you didn’t close the string with a matching double quote. With a
backslash at the end, you can keep writing the same string on the next
line.
When you print() a multiline string that’s broken up by backslashes,
the output is displayed on a single line:
>>> long_string = "This multiline string is \
displayed on one line"
>>> print(long_string)
This multiline string is displayed on one line
You can also create multiline strings using triple quotes (""" or ''') as
delimiters. Here’s how to write a long paragraph using this approach:
paragraph = """This planet has—or rather had—a problem, which was
this: most of the people living on it were unhappy for pretty much
of the time. Many solutions were suggested for this problem, but
most of these were largely concerned with the movements of small
green pieces of paper, which is odd because on the whole it wasn't
the small green pieces of paper that were unhappy."""
68
6. static.realpython.com/python-basics-sample-chapters.pdf, page 64
3.5. Leave Yourself Helpful Notes
3.5 Leave Yourself Helpful Notes
Programmers sometimes read code they wrote a while ago and wonder, “What does this do?” When you haven’t looked at code in a while,
it can be difficult to remember why you wrote it the way you did!
To help avoid this problem, you can leave comments in your code.
Comments are lines of text that don’t affect the way a program runs.
They document what code does or why the programmer made certain
decisions.
How to Write a Comment
The most common way to write a comment is to begin a new line in
your code with the # character. When you run your code, Python ignores lines starting with #.
Comments that start on a new line are called block comments. You
can also write inline comments, which are comments that appear
on the same line as the code they reference. Just put a # at the end of
the line of code, followed by the text in your comment.
Here’s an example of a program with both kinds of comments:
# This is a block comment.
greeting = "Hello, World"
print(greeting)
# This is an inline comment.
Of course, you can still use the # symbol inside a string. For instance,
Python won’t mistake the following for the start of a comment:
>>> print("#1")
#1
In general, it’s a good idea to keep comments as short as possible, but
sometimes you need to write more than reasonably fits on a single line.
In that case, you can continue your comment on a new line that also
begins with the # symbol:
58
3.5. Leave Yourself Helpful Notes
# This is my first program.
# It prints the phrase "Hello, World"
# The comments are longer than the code!
greeting = "Hello, World"
print(greeting)
You can also use comments to comment out code while you’re testing a program. Putting a # at the beginning of a line of code lets you
run your program as if that line of code didn’t exist, but it doesn’t actually delete the code.
To comment out a section of code in IDLE, highlight one or more lines
to be commented and press:
• Windows: Alt + 3
• macOS: Ctrl + 3
• Ubuntu Linux: Ctrl + D
To remove comments, highlight the commented lines and press:
• Windows: Alt + 4
• macOS: Ctrl + 4
• Ubuntu Linux: Ctrl + Shift + D
Now let’s look at some common conventions for code comments.
Conventions and Pet Peeves
According to PEP 8, comments should always be written in complete
sentences with a single space between the # and the first word of the
comment:
# This comment is formatted to PEP 8.
#this one isn't
For inline comments, PEP 8 recommends at least two spaces between
59
3.6. Summary and Additional Resources
the code and the # symbol:
phrase = "Hello, World"
# This comment is PEP 8 compliant.
print(phrase)# This comment isn't.
PEP 8 recommends that comments be used sparingly. A major pet
peeve among programmers is comments that describe what is already
obvious from reading the code.
For example, the comment in the following code is unnecessary:
# Print "Hello, World"
print("Hello, World")
The comment is unnecessary because the code itself explicitly describes what’s happening. Comments are best used to clarify code
that may be difficult to understand or to explain why something is
coded a certain way.
3.6
Summary and Additional Resources
In this chapter, you wrote and executed your first Python program!
You wrote a small program that displays the text "Hello, World" using
the print() function.
Then you learned about syntax errors, which occur before IDLE executes a program that contains invalid Python code, and runtime
errors, which only occur while a program is running.
You saw how to assign values to variables using the assignment
operator (=) and how to inspect variables in the interactive window.
Finally, you learned how to write helpful comments in your code for
when you or someone else looks at it in the future.
60
3.6. Summary and Additional Resources
Interactive Quiz
This chapter comes with a free online quiz to check your learning progress. You can access the quiz using your phone or computer at the following web address:
realpython.com/quizzes/pybasics-first-program
Additional Resources
To learn more, check out the following resources:
• “11 Beginner Tips for Learning Python Programming”
• “Writing Comments in Python (Guide)”
For links and additional resources to further deepen your Python
skills, visit realpython.com/python-basics/resources
61
Chapter 4
Strings and String Methods
Many programmers, regardless of their specialty, deal with text on a
daily basis. For example, web developers work with text input from
web forms. Data scientists process text to extract data and perform
tasks like sentiment analysis, which can help identify and classify
opinions in a body of text.
Collections of text in Python are called strings. Special functions
called string methods are used to manipulate strings. There are
string methods for changing a string from lowercase to uppercase, removing whitespace from the beginning or end of a string, replacing
parts of a string with different text, and much more.
In this chapter, you’ll learn how to:
• Manipulate strings with string methods
• Work with user input
• Deal with strings of numbers
• Format strings for printing
Let’s get started!
62
4.1
What Is a String?
4.1. What Is a String?
In chapter 3, you created the string "Hello, World" and printed it in
IDLE’s interactive window using print(). In this section, you’ll get a
deeper look into exactly what strings are and the various ways you can
create them in Python.
The String Data Type
Strings are one of the fundamental Python data types. The term data
type refers to what kind of data a value represents. Strings are used
to represent text.
Note
There are several other data types built into Python. For example, you’ll learn about numerical data types in chapter 5 and
Boolean data types in chapter 8.
We say that strings are a fundamental data type because they can’t
be broken down into smaller values of a different type. Not all data
types are fundamental. You’ll learn about compound data types, also
known as data structures, in chapter 9.
The string data type has a special abbreviated name in Python: str.
You can see this by using type(), which is a function used to determine
the data type of a given value.
Type the following into IDLE’s interactive window:
>>> type("Hello, World")
<class 'str'>
The output <class 'str'> indicates that the value "Hello, World" is an
instance of the str data type. That is, "Hello, World" is a string.
63
7. static.realpython.com/python-basics-sample-chapters.pdf, page 72
4.1. What Is a String?
Multiline Strings
The PEP 8 style guide recommends that each line of Python code contain no more than seventy-nine characters—including spaces.
Note
PEP 8’s seventy-nine-character line length is a recommendation, not a rule. Some Python programmers prefer a slightly
longer line length.
In this book, we’ll strictly follow PEP 8’s recommended line
length.
Whether you follow PEP 8 or choose a longer line length, sometimes
you’ll need to create string literals with more characters than your chosen limit.
To deal with long strings, you can break them up across multiple lines
into multiline strings. For example, suppose you need to fit the
following text into a string literal:
This planet has—or rather had—a problem, which was
this: most of the people living on it were unhappy for
pretty much of the time. Many solutions were suggested
for this problem, but most of these were largely concerned with the movements of small green pieces of
paper, which is odd because on the whole it wasn’t the
small green pieces of paper that were unhappy.
— Douglas Adams, The Hitchhiker’s Guide to the Galaxy
This paragraph contains far more than seventy-nine characters, so
any line of code containing the paragraph as a string literal violates
PEP 8. So, what do you do?
There are a couple of ways to tackle this. One way is to break the string
up across multiple lines and put a backslash (\) at the end of all but the
67
4.1. What Is a String?
last line. To be PEP 8 compliant, the total length of the line, including
the backslashes, must be seventy-nine characters or fewer.
Here’s how you could write the paragraph as a multiline string using
the backslash method:
paragraph = "This planet has—or rather had—a problem, which was \
this: most of the people living on it were unhappy for pretty much \
of the time. Many solutions were suggested for this problem, but \
most of these were largely concerned with the movements of small \
green pieces of paper, which is odd because on the whole it wasn't \
the small green pieces of paper that were unhappy."
Notice that you don’t have to close each line with a quotation mark.
Normally, Python would get to the end of the first line and complain
that you didn’t close the string with a matching double quote. With a
backslash at the end, you can keep writing the same string on the next
line.
When you print() a multiline string that’s broken up by backslashes,
the output is displayed on a single line:
>>> long_string = "This multiline string is \
displayed on one line"
>>> print(long_string)
This multiline string is displayed on one line
You can also create multiline strings using triple quotes (""" or ''') as
delimiters. Here’s how to write a long paragraph using this approach:
paragraph = """This planet has—or rather had—a problem, which was
this: most of the people living on it were unhappy for pretty much
of the time. Many solutions were suggested for this problem, but
most of these were largely concerned with the movements of small
green pieces of paper, which is odd because on the whole it wasn't
the small green pieces of paper that were unhappy."""
68
4.2. Concatenation, Indexing, and Slicing
Triple-quoted strings preserve whitespace, including newlines. This
means that running print(paragraph) would display the string on multiple lines, just as it appears in the string literal. This may or may not
be what you want, so you’ll need to think about the desired output
before you choose how to write a multiline string.
To see how whitespace is preserved in a triple-quoted string, type the
following into IDLE’s interactive window:
>>> print("""An example of a
...
string that spans across multiple lines
...
and also preserves whitespace.""")
An example of a
string that spans across multiple lines
and also preserves whitespace.
Notice how the second and third lines in the output are indented in
exactly the same way as the string literal.
Review Exercises
You can nd the solutions to these exercises and many other bonus
resources online at realpython.com/python-basics/resources
1. Print a string that uses double quotation marks inside the string.
2. Print a string that uses an apostrophe inside the string.
3. Print a string that spans multiple lines with whitespace preserved.
4. Print a string that is coded on multiple lines but gets printed on a
single line.
4.2 Concatenation, Indexing, and
Slicing
Now that you know what a string is and how to declare string literals
in your code, let’s explore some of the things you can do with strings.
69
4.2. Concatenation, Indexing, and Slicing
In this section, you’ll learn about three basic string operations:
1. Concatenation, which joins two strings together
2. Indexing, which gets a single character from a string
3. Slicing, which gets several characters from a string at once
Let’s dive in!
String Concatenation
You can combine, or concatenate, two strings using the + operator:
>>> string1 = "abra"
>>> string2 = "cadabra"
>>> magic_string = string1 + string2
>>> magic_string
'abracadabra'
In this example, the string concatenation occurs on the third line. You
concatenate string1 and string2 using +, and then you assign the result to the variable magic_string. Notice that the two strings are joined
without any whitespace between them.
You can use string concatenation to join two related strings, such as
joining a first name and a last name into a full name:
>>> first_name = "Arthur"
>>> last_name = "Dent"
>>> full_name = first_name + " " + last_name
>>> full_name
'Arthur Dent'
Here, you use string concatenation twice on the same line. First, you
concatenate first_name with " " to ensure a space appears after the
first name in the final string. This produces the string "Arthur ", which
you then concatenate with last_name to produce the full name "Arthur
Dent".
70
4.2. Concatenation, Indexing, and Slicing
String Indexing
Each character in a string has a numbered position called an index.
You can access the character at the nth position by putting the number
n between two square brackets ([]) immediately after the string:
>>> flavor = "fig pie"
>>> flavor[1]
'i'
flavor[1] returns the character at position 1 in "fig pie", which is i.
Wait. Isn’t f the first character of "fig pie"?
In Python—and in most other programming languages—counting always starts at zero. To get the character at the beginning of a string,
you need to access the character at position 0:
>>> flavor[0]
'f'
Important
Forgetting that counting starts with zero and trying to access
the first character in a string with the index 1 results in an o by-one error.
Off-by-one errors are a common source of frustration for beginning and experienced programmers alike!
The following figure shows the index for each character of the string
"fig pie":
|
f
0
|
i
1
|
g
2
|
|
3
p
4
|
i
5
|
e
|
6
71
8. static.realpython.com/python-basics-sample-chapters.pdf, page 75
4.2. Concatenation, Indexing, and Slicing
In this section, you’ll learn about three basic string operations:
1. Concatenation, which joins two strings together
2. Indexing, which gets a single character from a string
3. Slicing, which gets several characters from a string at once
Let’s dive in!
String Concatenation
You can combine, or concatenate, two strings using the + operator:
>>> string1 = "abra"
>>> string2 = "cadabra"
>>> magic_string = string1 + string2
>>> magic_string
'abracadabra'
In this example, the string concatenation occurs on the third line. You
concatenate string1 and string2 using +, and then you assign the result to the variable magic_string. Notice that the two strings are joined
without any whitespace between them.
You can use string concatenation to join two related strings, such as
joining a first name and a last name into a full name:
>>> first_name = "Arthur"
>>> last_name = "Dent"
>>> full_name = first_name + " " + last_name
>>> full_name
'Arthur Dent'
Here, you use string concatenation twice on the same line. First, you
concatenate first_name with " " to ensure a space appears after the
first name in the final string. This produces the string "Arthur ", which
you then concatenate with last_name to produce the full name "Arthur
Dent".
70
4.2. Concatenation, Indexing, and Slicing
String Indexing
Each character in a string has a numbered position called an index.
You can access the character at the nth position by putting the number
n between two square brackets ([]) immediately after the string:
>>> flavor = "fig pie"
>>> flavor[1]
'i'
flavor[1] returns the character at position 1 in "fig pie", which is i.
Wait. Isn’t f the first character of "fig pie"?
In Python—and in most other programming languages—counting always starts at zero. To get the character at the beginning of a string,
you need to access the character at position 0:
>>> flavor[0]
'f'
Important
Forgetting that counting starts with zero and trying to access
the first character in a string with the index 1 results in an o by-one error.
Off-by-one errors are a common source of frustration for beginning and experienced programmers alike!
The following figure shows the index for each character of the string
"fig pie":
|
f
0
|
i
1
|
g
2
|
|
3
p
4
|
i
5
|
e
|
6
71
4.2. Concatenation, Indexing, and Slicing
If you try to access an index beyond the end of a string, then Python
raises an IndexError:
>>> flavor[9]
Traceback (most recent call last):
File "<pyshell#4>", line 1, in <module>
flavor[9]
IndexError: string index out of range
The largest index in a string is always one less than the string’s length.
Since "fig pie" has a length of seven, the largest index allowed is 6.
Strings also support negative indices:
>>> flavor[-1]
'e'
The last character in a string has index -1, which for "fig pie" is the
letter e. The second to last character i has index -2, and so on.
The following figure shows the negative index for each character in
the string "fig pie":
|
f
|
-7
i
-6
|
g
-5
|
|
-4
p
-3
|
i
-2
|
e
|
-1
Just like with positive indices, Python raises an IndexError if you try to
access a negative index less than the index of the first character in the
string:
>>> flavor[-10]
Traceback (most recent call last):
File "<pyshell#5>", line 1, in <module>
flavor[-10]
IndexError: string index out of range
Negative indices may not seem useful at first, but sometimes they’re
a better choice than a positive index.
72
4.2. Concatenation, Indexing, and Slicing
For example, suppose a string input by a user is assigned to the variable user_input. If you need to get the last character of the string, how
do you know what index to use?
One way to get the last character of a string is to calculate the final
index using len():
final_index = len(user_input) - 1
last_character = user_input[final_index]
Getting the final character with the index -1 takes less typing and
doesn’t require an intermediate step to calculate the final index:
last_character = user_input[-1]
String Slicing
Suppose you need a string containing just the first three letters of the
string "fig pie". You could access each character by index and concatenate them like this:
>>> first_three_letters = flavor[0] + flavor[1] + flavor[2]
>>> first_three_letters
'fig'
If you need more than just the first few letters of a string, then getting each character individually and concatenating them together is
clumsy and long-winded. Fortunately, Python provides a way to do
this with much less typing.
You can extract a portion of a string, called a substring, by inserting
a colon between two index numbers set inside square brackets like
this:
>>> flavor = "fig pie"
>>> flavor[0:3]
'fig'
73
4.2. Concatenation, Indexing, and Slicing
flavor[0:3] returns the first three characters of the string assigned to
flavor, starting with the character at index 0 and going up to but not including the character at index 3. The [0:3] part of flavor[0:3] is called
a slice. In this case, it returns a slice of "fig pie". Yum!
String slices can be confusing because the substring returned by
the slice includes the character whose index is the first number but
doesn’t include the character whose index is the second number.
To remember how slicing works, you can think of a string as a sequence of square slots. The left and right boundaries of each slot are
numbered sequentially from zero up to the length of the string, and
each slot is filled with a character in the string.
Here’s what this looks like for the string "fig pie":
|
f
0
|
1
i
|
2
g
|
|
3
4
p
|
5
i
|
6
e
|
7
So, for "fig pie", the slice [0:3] returns the string "fig", and the slice
[3:7] returns the string " pie".
If you omit the first index in a slice, then Python assumes you want to
start at index 0:
>>> flavor[:3]
'fig'
The slice [:3] is equivalent to the slice [0:3], so flavor[:3] returns the
first three characters in the string "fig pie".
Similarly, if you omit the second index in the slice, then Python assumes you want to return the substring that begins with the character
74
9. edu.anarcho-copy.org/Programming%20Languages/Python/Automate%20the%20Boring%20Stuff%20with%20Python.pdf, page 149
Practice Projects
For practice, write programs to do the following tasks.
Fantasy Game Inventory
You are creating a fantasy video game. The data structure to model the
player’s inventory will be a dictionary where the keys are string values
describing the item in the inventory and the value is an integer value detailing how many of that item the player has. For example, the dictionary value
{'rope': 1, 'torch': 6, 'gold coin': 42, 'dagger': 1, 'arrow': 12} means the
player has 1 rope, 6 torches, 42 gold coins, and so on.
Write a function named displayInventory() that would take any possible
“inventory” and display it like the following:
Inventory:
12 arrow
42 gold coin
1 rope
6 torch
1 dagger
Total number of items: 62
Hint: You can use a for loop to loop through all the keys in a dictionary.
# inventory.py
stuff = {'rope': 1, 'torch': 6, 'gold coin': 42, 'dagger': 1, 'arrow': 12}
def displayInventory(inventory):
print("Inventory:")
item_total = 0
for k, v in inventory.items():
print(str(v) + ' ' + k)
item_total += v
print("Total number of items: " + str(item_total))
displayInventory(stuff)
List to Dictionary Function for Fantasy Game Inventory
Imagine that a vanquished dragon’s loot is represented as a list of strings
like this:
dragonLoot = ['gold coin', 'dagger', 'gold coin', 'gold coin', 'ruby']
Write a function named addToInventory(inventory, addedItems), where the
inventory parameter is a dictionary representing the player’s inventory (like
in the previous project) and the addedItems parameter is a list like dragonLoot.
120 Chapter 5
The addToInventory() function should return a dictionary that represents the
updated inventory. Note that the addedItems list can contain multiples of the
same item. Your code could look something like this:
def addToInventory(inventory, addedItems):
# your code goes here
inv = {'gold coin': 42, 'rope': 1}
dragonLoot = ['gold coin', 'dagger', 'gold coin', 'gold coin', 'ruby']
inv = addToInventory(inv, dragonLoot)
displayInventory(inv)
The previous program (with your displayInventory() function from the
previous project) would output the following:
Inventory:
45 gold coin
1 rope
1 ruby
1 dagger
Total number of items: 48
Dictionaries and Structuring Data 121
6
Ma n i p u l a t i n g S t r i n g s
Text is one of the most common forms
of data your programs will handle. You
already know how to concatenate two string
values together with the + operator, but you
can do much more than that. You can extract partial
strings from string values, add or remove spacing, convert letters to lowercase or uppercase, and check that strings are formatted correctly. You can
even write Python code to access the clipboard for copying and pasting text.
In this chapter, you’ll learn all this and more. Then you’ll work through
two different programming projects: a simple password manager and a program to automate the boring chore of formatting pieces of text.
Working with Strings
Let’s look at some of the ways Python lets you write, print, and access strings
in your code.
String Literals
Typing string values in Python code is fairly straightforward: They begin
and end with a single quote. But then how can you use a quote inside a
string? Typing 'That is Alice's cat.' won’t work, because Python thinks
the string ends after Alice, and the rest (s cat.') is invalid Python code.
Fortunately, there are multiple ways to type strings.
Double Quotes
Strings can begin and end with double quotes, just as they do with single
quotes. One benefit of using double quotes is that the string can have a
single quote character in it. Enter the following into the interactive shell:
>>> spam = "That is Alice's cat."
Since the string begins with a double quote, Python knows that the
single quote is part of the string and not marking the end of the string.
However, if you need to use both single quotes and double quotes in the
string, you’ll need to use escape characters.
Escape Characters
An escape character lets you use characters that are otherwise impossible to
put into a string. An escape character consists of a backslash (\) followed
by the character you want to add to the string. (Despite consisting of two
characters, it is commonly referred to as a singular escape character.) For
example, the escape character for a single quote is \'. You can use this
inside a string that begins and ends with single quotes. To see how escape
characters work, enter the following into the interactive shell:
>>> spam = 'Say hi to Bob\'s mother.'
Python knows that since the single quote in Bob\'s has a backslash, it
is not a single quote meant to end the string value. The escape characters
\' and \" let you put single quotes and double quotes inside your strings,
respectively.
Table 6-1 lists the escape characters you can use.
Table 6-1: Escape Characters
124 Chapter 6
Escape character
Prints as
\'
Single quote
\"
Double quote
\t
Tab
\n
Newline (line break)
\\
Backslash
Enter the following into the interactive shell:
>>> print("Hello there!\nHow are you?\nI\'m doing fine.")
Hello there!
How are you?
I'm doing fine.
Raw Strings
You can place an r before the beginning quotation mark of a string to make
it a raw string. A raw string completely ignores all escape characters and
prints any backslash that appears in the string. For example, type the following into the interactive shell:
>>> print(r'That is Carol\'s cat.')
That is Carol\'s cat.
Because this is a raw string, Python considers the backslash as part of
the string and not as the start of an escape character. Raw strings are helpful if you are typing string values that contain many backslashes, such as the
strings used for regular expressions described in the next chapter.
Multiline Strings with Triple Quotes
While you can use the \n escape character to put a newline into a string, it
is often easier to use multiline strings. A multiline string in Python begins
and ends with either three single quotes or three double quotes. Any quotes,
tabs, or newlines in between the “triple quotes” are considered part of the
string. Python’s indentation rules for blocks do not apply to lines inside a
multiline string.
Open the file editor and write the following:
print('''Dear Alice,
Eve's cat has been arrested for catnapping, cat burglary, and extortion.
Sincerely,
Bob''')
Save this program as catnapping.py and run it. The output will look
like this:
Dear Alice,
Eve's cat has been arrested for catnapping, cat burglary, and extortion.
Sincerely,
Bob
Manipulating Strings 125
10. static.realpython.com/python-basics-sample-chapters.pdf, page 98
4.7. Streamline Your Print Statements
Review Exercises
You can nd the solutions to these exercises and many other bonus
resources online at realpython.com/python-basics/resources
1. Create a string containing an integer, then convert that string into
an actual integer object using int(). Test that your new object is
a number by multiplying it by another number and displaying the
result.
2. Repeat the previous exercise, but use a floating-point number and
float().
3. Create a string object and an integer object, then display them side
by side with a single print statement using str().
4. Write a program that uses input() twice to get two numbers from
the user, multiplies the numbers together, and displays the result.
If the user enters 2 and 4, then your program should print the
following text:
The product of 2 and 4 is 8.0.
4.7 Streamline Your Print Statements
Suppose you have a string, name = "Zaphod", and two integers, heads
= 2 and arms = 3. You want to display them in the string "Zaphod has
2 heads and 3 arms". This is called string interpolation, which is
just a fancy way of saying that you want to insert some variables into
specific locations in a string.
One way to do this is with string concatenation:
>>> name + " has " + str(heads) + " heads and " + str(arms) + " arms"
'Zaphod has 2 heads and 3 arms'
This code isn’t the prettiest, and keeping track of what goes inside or
outside the quotes can be tough. Fortunately, there’s another way of
interpolating strings: formatted string literals, more commonly
94
4.7. Streamline Your Print Statements
known as f-strings.
The easiest way to understand f-strings is to see them in action. Here’s
what the above string looks like when written as an f-string:
>>> f"{name} has {heads} heads and {arms} arms"
'Zaphod has 2 heads and 3 arms'
There are two important things to notice about the above example:
1. The string literal starts with the letter f before the opening quotation mark.
2. Variable names surrounded by curly braces ({}) are replaced by
their corresponding values without using str().
You can also insert Python expressions between the curly braces. The
expressions are replaced with their result in the string:
>>> n = 3
>>> m = 4
>>> f"{n} times {m} is {n*m}"
'3 times 4 is 12'
It’s a good idea to keep any expressions used in an f-string as simple
as possible. Packing a bunch of complicated expressions into a string
literal can result in code that is difficult to read and difficult to maintain.
f-strings are available only in Python version 3.6 and above. In earlier versions of Python, you can use .format() to get the same results.
Returning to the Zaphod example, you can use .format() to format the
string like this:
>>> "{} has {} heads and {} arms".format(name, heads, arms)
'Zaphod has 2 heads and 3 arms'
f-strings are shorter and sometimes more readable than using .format(). You’ll see f-strings used throughout this book.
95
4.8. Find a String in a String
For an in-depth guide to f-strings and comparisons to other string formatting techniques, check out Real Python’s “Python 3’s f-Strings: An
Improved String Formatting Syntax (Guide).”
Review Exercises
You can nd the solutions to these exercises and many other bonus
resources online at realpython.com/python-basics/resources
1. Create a float object named weight with the value 0.2, and create
a string object named animal with the value "newt". Then use these
objects to print the following string using only string concatenation:
0.2 kg is the weight of the newt.
2. Display the same string by using .format() and empty {} placeholders.
3. Display the same string using an f-string.
4.8 Find a String in a String
One of the most useful string methods is .find(). As its name implies,
this method allows you to find the location of one string in another
string—commonly referred to as a substring.
To use .find(), tack it to the end of a variable or a string literal with
the string you want to find typed between the parentheses:
>>> phrase = "the surprise is in here somewhere"
>>> phrase.find("surprise")
4
The value that .find() returns is the index of the first occurrence of the
string you pass to it. In this case, "surprise" starts at the fifth character
of the string "the surprise is in here somewhere", which has index 4
because counting starts at zero.
96
This is a sample from “Python Basics: A Practical
Introduction to Python 3”
With the full version of the book you get a complete Python curriculum
to go all the way from beginner to intermediate-level. Every step along
the way is explained and illustrated with short & clear code samples.
Coding exercises within each chapter and our interactive quizzes help
fast-track your progress and ensure you always know what to focus on
next.
Become a fluent Pythonista and gain programming knowledge you
can apply in the real-world, today:
If you enjoyed the sample chapters you can purchase a full
version of the book at realpython.com/pybasics-book
[1] https://static.realpython.com/python-basics-sample-chapters.pdf#page=96
[2] https://static.realpython.com/python-basics-sample-chapters.pdf#page=94
[3] https://edu.anarcho-copy.org/Programming%20Languages/Python/Automate%20the%20Boring%20Stuff%20with%20Python.pdf#page=490
[4] https://edu.anarcho-copy.org/Programming%20Languages/Python/Automate%20the%20Boring%20Stuff%20with%20Python.pdf#page=500
[5] https://static.realpython.com/python-basics-sample-chapters.pdf#page=69
[6] https://static.realpython.com/python-basics-sample-chapters.pdf#page=64
[7] https://static.realpython.com/python-basics-sample-chapters.pdf#page=72
[8] https://static.realpython.com/python-basics-sample-chapters.pdf#page=75
[9] https://edu.anarcho-copy.org/Programming%20Languages/Python/Automate%20the%20Boring%20Stuff%20with%20Python.pdf#page=149
[10] https://static.realpython.com/python-basics-sample-chapters.pdf#page=98