Chapter 3 — Input, Output & Strings
The module's primary reading · ~35–45 minutes · Objective 2 (use variables and the core types int, float, str, and bool; evaluate expressions with correct operator precedence, including true division, floor division, and remainder; convert between types; and read input and build output with indexing, slicing, and f-strings) · Read it first this week; the lecture, the slides, the tutorial, the quiz, and the Coding Lab all build on it.
In plain language
Most programs you use talk with a person: they ask a question, wait for an answer, and reply. This week your programs do that too. You will use input() (Python's way of asking the person at the keyboard to type something) and learn that whatever comes back is text, even when the person types digits. You will build replies with f-strings (strings that fill in values for you), and you will take text apart one character (one letter, digit, space, or mark) at a time or one piece at a time. As always, you predict what each line prints and then run it to check.
Why you already care about this
You walk up to a café kiosk, tap in your name, Mariana, and order 2 lattes. The screen thanks you by name, a printed slip says "Order for Mariana: 2 lattes," and the cup label has room for only 3 letters, so it says MAR. In those few seconds, a program asked you for text, kept it, built a new sentence around it, and cut off a piece of it.
Now picture a sign-up form that asks your age. You type 25. The form has no idea that "25" is a number; it sees a 2 and a 5, two characters in a row. If the program tries to add 1 to that without converting it first, it either stops with an error or does something strange. Typed text is text until you say otherwise.
This chapter teaches you to ask for input, convert it on purpose, build output with f-strings, and pick characters out of a string by their position. The reading log from Weeks 1 and 2 learns its book's title this week, and you will take that title apart letter by letter.
By the end of this chapter you will be able to:
- read a typed value with
input()and convert it withint()before doing arithmetic; - build a line of output with an f-string that fills in names and expressions;
- pick one character from a string with an index, counting from 0 or back from the end;
- cut a piece from a string with a slice, and say exactly which characters it keeps;
- count a string's characters with
len()and predict when an index raises an IndexError; - check a chatbot's claim about a slice by running the line yourself.
Carry this line with you: typed text stays text — convert it before you count with it.
Where we are
- Already covered: Week 1 taught you to predict what a line prints, run it, and read an error from its last line. Week 2 gave values names, sorted them into the types int, float, str, and bool, and showed you
int()andstr(). - This week:
input(), f-strings, indexing, slicing,len(), and the IndexError. - How they connect: every value
input()hands you is a str, so Week 2's conversions become an everyday tool, and Week 1's habit of reading the last line of an error now meets a new type. - Where we're going next: Week 4, Booleans & Conditionals, teaches a program to choose which line runs, often based on what the user typed.
Two Week 2 ideas carry most of the weight this week. First, "5" + 3 raised a TypeError, because Python will not mix a string and a number with +. Second, "3" * 4 printed 3333, because * repeats a string. Keep both in mind, because typed input is always a string. Spend extra time on Sections 3 and 4; Week 11 builds its text processing on them.
1. Ask the keyboard: typed input is always a string
A librarian at a help desk asks, "What book are you looking for?" and writes your answer on a slip. Whatever you say, the slip holds words in ink. If you say a number out loud, the slip does not hold an amount you can add; it holds marks in ink. A program that asks a question works the same way.
input() is the built-in function that shows a prompt, waits for the user to type a line and press Enter, and hands back exactly what was typed as a string.
A prompt is the message input() shows on the screen to tell the user what to type, such as Book title: followed by a space.
Worked example — the reading log asks for its book. The user types the river book and presses Enter.
book = input("Book title: ")
print(book)
print(type(book))
Output
Book title: the river book
the river book
<class 'str'>
The first output line shows the prompt and, right after it, what the user typed. Line 2 printed the stored text. Line 3 confirmed its type: <class 'str'>, a string. To pin a run that does not depend on what anyone types, this course writes the typed value as a literal instead: book = "the river book". The rest of the chapter uses that literal.
Worked example — the user types digits. Now the user types 25. The pinned run stores that typed value as the literal typed = "25". Predict each line before you read the output.
typed = "25"
print(type(typed))
print(typed * 2)
age = int(typed)
print(age + 1)
Output
<class 'str'>
2525
26
Here is the reasoning, line by line.
type(typed)reports <class 'str'>. Two digits in quotation marks are text.typed * 2repeats the text, as Week 2's"3" * 4did. Two copies of "25" side by side print 2525, not 50.int(typed)turns the text "25" into the whole number 25, andagegets that number.age + 1works out 25 + 1 = 26, and Python prints 26.
In words: the conversion is the step that turns typed digits into a number you can do arithmetic with. A program that skips it prints 2525 where you wanted 50, a value 50.5 times too large, with no error to warn you.
Skip the conversion with + and Python refuses outright. print(typed + 1) prints nothing, and the last line of its error message names TypeError, the same type Week 2 met with "5" + 3.
Worked example — today's pages in the reading log. The reading log already holds pages_read = 45. It asks how many pages you read today, and the user types 30, which the pinned run writes as pages_today = "30".
pages_read = 45
pages_today = "30"
print(pages_read + int(pages_today))
Output
75
int(pages_today) turns "30" into 30, then 45 + 30 = 75. In words: after today, the log stands at 75 pages read.
Misconception check. Students often think
input()gives a number when the user types digits. That is tempting, because 25 on the screen looks like a number. Butinput()always hands back a string, so "25" is two characters of text. The cure is a habit: wrapint()around typed digits before any arithmetic, and asktype()whenever a value surprises you.
In practice (your tools). Open your free browser Python runner and type book = input("Book title: ") on line 1 and print(type(book)) on line 2. Press Run. The output panel shows the prompt and waits; click into it, type any title, and press Enter. Then run it again and type only digits, such as 25. The type is still str both times. The rule is written in the Standard Library reference, built-in functions, under input(), on docs.python.org.
Memory hook: typed text stays text — convert it before you count with it.
2. Build output with f-strings, not glue
A coffee-shop slip that says "Order for Mariana: 2 lattes" was not typed by hand for every customer. Somebody wrote a template, "Order for ___: ___ lattes," and the register fills in the blanks. Python's f-strings are that template.
An f-string is a string with the letter f right before its opening quote, in which every pair of curly braces holds a name or an expression whose value Python fills in.
Worked example — the reading log prints its status. The book's title and the page count go into two f-strings.
book = "the river book"
pages_read = 45
print(f"Now reading: {book}")
print(f"{pages_read} pages read so far")
Output
Now reading: the river book
45 pages read so far
Line 3 put the text stored in book where {book} sat. Line 4 put the number 45 where {pages_read} sat, and you did not need str() first; the f-string handled the number for you. In words: the braces are blanks, and Python fills each one with a value.
The braces can hold a whole expression, not only a name. Here is the pinned typed-value program's last line, with age holding 25 from Section 1.
age = 25
print(f"Next year you will be {age + 1}")
Output
Next year you will be 26
Python worked out 25 + 1 = 26 inside the braces, then put 26 into the sentence.
Here is the café slip, an illustrative order of 2 lattes at 4 dollars each.
name = "Mariana"
cups = 2
print(f"Order for {name}: {cups} lattes")
print(f"Total: {cups * 4} dollars")
Output
Order for Mariana: 2 lattes
Total: 8 dollars
Before f-strings, you had to glue pieces together. Concatenation is joining two strings end to end with the + operator, which works only when both sides are strings. You will see it here once, because it is what f-strings replace.
book = "the river book"
print("Now reading: " + book)
Output
Now reading: the river book
That works, because both sides are strings. Now try to glue a number on.
pages_read = 45
print(pages_read + " pages read so far")
Output
TypeError
Nothing printed. The left side of + is the number 45 and the right side is text, so Python raised a TypeError rather than guess. The f-string version from the worked example printed the same sentence with no conversion at all. That is why this course uses f-strings for formatted output from this week on.
Misconception check. Students often think a string without the
fin front fills in{name}anyway. It does not. Without thef, the braces are ordinary characters. Withpages_read = 45, the lineprint("{pages_read} pages read so far")prints{pages_read} pages read so far, braces and all. The cure: when braces show up in your output, look for the missingfright before the opening quote.
In practice (your tools). In your browser runner, run print(f"{pages_read} pages read so far") after setting pages_read = 45, then delete the f and run again. Compare the two outputs character by character. The Python Tutorial's section 7.1.1, Formatted String Literals, on docs.python.org, is the official description; f-strings arrived in Python 3.6 under PEP 498.
Memory hook: the f fills the blanks; no f, no filling.
3. Pick one character: indexing from 0 and from the end
Think of a row of lockers in a gym. Each locker has a number painted on it, and you open one by its number. Now imagine the first locker is painted 0, not 1. That is how Python numbers the characters in a string.
A character is one letter, digit, space, or punctuation mark; a string is a row of characters kept in order.
An index is a whole number in square brackets after a string that picks out the one character at that position, counting from 0 at the left.
Zero-based indexing is numbering the positions in a string starting from 0, so the first character sits at index 0 and the last sits at the length minus 1.
Here is the reading log's title with each index written under its character. The table lists the first ten positions; the spaces count, because a space is a character too.
| Index | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
|---|---|---|---|---|---|---|---|---|---|---|
| Character | t | h | e | (space) | r | i | v | e | r | (space) |
Worked example — first characters. Predict both lines.
book = "the river book"
print(book[0])
print(book[4])
Output
t
r
book[0] is the first character, t. book[4] is the fifth character, r, the start of the word river: index 0 is t, 1 is h, 2 is e, 3 is the space, and 4 is r. In words: the index counts how many characters come before the one you want.
Counting from the end is often handier. A negative index is an index below zero that counts back from the end of a string, so an index of minus 1 picks the last character and minus 2 the one before it.
book = "the river book"
print(book[-1])
print("cat"[-1])
Output
k
t
book[-1] is the last character of the title, k. "cat"[-1] is the last character of cat, t. You never need to know a string's length to reach its last character this way.
The same tool works on any text. A bike-share dock might carry the illustrative label B12.
dock = "B12"
print(dock[0])
print(dock[-1])
Output
B
2
The first character is the letter B and the last is the character 2. Both are strings, not numbers, even the 2.
Misconception check. Students often think the last character of
"cat"iss[3], because cat has 3 letters and people count from 1. That is tempting, but the indexes of cat are 0, 1, and 2, so index 3 is past the end. Ask for it and Python raises an IndexError, which Section 5 covers. The cure: the last character is at index-1, or at the length minus 1.
In practice (your tools). Paste book = "the river book" and print(book[4]) into Python Tutor at pythontutor.com and step forward. Then change the 4 to 0, to 3, and to -1, running each time, and predict before every run. When an index surprises you, write the string out with its indexes under it, as in the table above.
Memory hook: count from 0 on the left, from minus 1 on the right.
4. Cut a piece: slices keep the start and drop the stop
A baker slicing a loaf from the 4th cut mark to the 9th cut mark gets the bread between those marks. The 9th mark is where the knife stops, not a piece of bread you take home. Python's slices work the same way.
A slice is a piece cut from a string with square brackets and a colon, as in s[start:stop], which keeps the characters from index start up to, but not including, index stop.
A slice is half-open, which describes a slice that includes its start position and leaves out its stop position, so s[1:4] holds three characters.
Worked example — the river in the river book. Predict the output before you read it.
book = "the river book"
print(book[4:9])
Output
river
The slice starts at index 4, which is r, and stops before index 9, which is the space after river. It keeps the characters at indexes 4, 5, 6, 7, and 8: r, i, v, e, r. That is 9 − 4 = 5 characters. In words: stop minus start tells you how many characters a slice keeps.
The pinned predict-the-output snippet makes the same point with capital letters.
print("PYTHON"[1:4])
print("hello"[1:4])
Output
YTH
ell
"PYTHON"[1:4] keeps indexes 1, 2, and 3: Y, T, H. Index 4, the O, is the stop, so it is left out. "hello"[1:4] keeps e, l, l the same way.
Leave out a number and Python fills in the obvious one: no start means "from the beginning," and no stop means "to the end."
book = "the river book"
print(book[:3])
print(book[10:])
Output
the
book
book[:3] keeps indexes 0, 1, and 2, the word the. book[10:] starts at index 10, the b of book, and runs to the end.
A third number is a step, the optional third number in a slice, as in s[start:stop:step], which says how many positions to move each time; a step of minus 1 walks backward through the string.
print("PYTHON"[::2])
print("hello"[::-1])
Output
PTO
olleh
"PYTHON"[::2] takes every second character from the start: P at index 0, T at 2, O at 4. "hello"[::-1] walks from the end to the start, so it prints the word backward.
Misconception check. Students often think
s[1:4]includes index 4, because "from 1 to 4" sounds like it should. That is tempting, but the stop is where the slice ends, and the character at the stop is never kept."PYTHON"[1:4]prints YTH, not YTHO. The cure: count stop minus start, 4 − 1 = 3, and expect exactly that many characters.
In practice (your tools). In your browser runner, run print("PYTHON"[1:4]), then change the stop to 5 and run again; one more character, O, appears. The Python Tutorial's section 3.1.2, Text, on docs.python.org, shows the same rule, that s[:i] + s[i:] always rebuilds s exactly.
Memory hook: a slice keeps the start and drops the stop.
5. Count characters: the strict index and the forgiving slice
A cinema row has 14 seats numbered 0 to 13. Hand an usher a ticket for seat 14 and the usher stops you, because that seat does not exist. Hand the usher a request for "seats 4 through 99" and you get seats 4 to 13, the ones that exist. Strings treat a single index and a slice in that same strict-versus-forgiving way.
len() is the built-in function that counts the characters in a string, with spaces and punctuation counted too.
An IndexError is the error type Python reports when an index points to a position where no character sits, such as index 14 in a string of 14 characters.
Worked example — measuring the title. Count the characters yourself before you run it.
book = "the river book"
print(len(book))
print(book[13])
Output
14
k
The title has 14 characters: 3 letters in the, 5 in river, 4 in book, and 2 spaces, and 3 + 5 + 4 + 2 = 14. Because counting starts at 0, the last index is 14 − 1 = 13, and book[13] is k, the same character book[-1] gave you in Section 3.
Worked example — one step too far. Predict what happens.
book = "the river book"
print(book[14])
Output
IndexError
Nothing printed. Index 14 is one position past the last character, so Python stopped, and the last line of the error message names IndexError. This is a runtime error: the program started, and this line stopped it.
Worked example — the forgiving slice. Now ask for a slice that runs far past the end.
book = "the river book"
print(book[4:99])
Output
river book
No error. The slice started at index 4 and stopped quietly at the end of the string, because a slice takes whatever characters exist in its range. In words: an index must point at a real character, but a slice only promises "whatever is in here."
Here is len() in a different setting, a sign-up page that shows how long a new password is (an illustrative password).
password = "sunflower7"
print(len(password))
Output
10
Nine letters and one digit make 10 characters, and len() counts the digit like any other character.
Misconception check. Students often think the last index of a string equals its length, so they reach for
book[14]afterlen(book)prints 14. That is tempting, because people count from 1. But the indexes run from 0, so the last one is the length minus 1. The cure: usebook[-1]for the last character, or subtract 1 from the length, and remember that only a slice forgives a number past the end.
In practice (your tools). In your browser runner, run print(book[14]) and scroll to the last line of the error panel; it begins with IndexError. Then run print(book[4:99]) and see that the slice prints without complaint. The Standard Library reference, built-in exceptions, on docs.python.org, gives the one-line definition of IndexError.
Memory hook: an index must hit a character; a slice takes what is there.
6. Put it together and check a chatbot's claim
A ticket machine asks two questions, then prints a slip that uses both answers. Most small programs you will write in this course have that shape: ask, convert, build, print. Here is the reading log doing all four.
Worked example — the reading log talks back. The user types the river book at the first prompt and 30 at the second.
book = input("Book title: ")
pages_today = input("Pages read today: ")
pages_read = 45 + int(pages_today)
print(f"Now reading: {book}")
print(f"Short title: {book[4:9]}")
print(f"{pages_read} pages read so far")
Output
Book title: the river book
Pages read today: 30
Now reading: the river book
Short title: river
75 pages read so far
Trace it. Lines 1 and 2 store two strings, "the river book" and "30". Line 3 converts "30" to 30 and works out 45 + 30 = 75. Line 4 fills in the title. Line 5 fills in the slice book[4:9], which is river. Line 6 fills in 75. In words: the program asked twice, converted once, and built three lines of output.
Here is the same shape in a different setting, a temperature converter. The user types 20.
celsius = input("Temperature in Celsius: ")
fahrenheit = int(celsius) * 9 / 5 + 32
print(f"{celsius} Celsius is {fahrenheit} Fahrenheit")
Output
Temperature in Celsius: 20
20 Celsius is 68.0 Fahrenheit
int(celsius) turns "20" into 20, then 20 × 9 = 180, 180 ⁄ 5 = 36.0, and 36.0 + 32 = 68.0. The decimal point comes from /, which always gives a float, as Week 2 showed.
Worked example — checking a chatbot's claim. Suppose you ask a chatbot what print("PYTHON"[1:4]) displays, and it answers YTHO, explaining that the slice runs from index 1 to index 4. That sounds reasonable. Your job is to check it, not to believe it.
print("PYTHON"[1:4])
Output
YTH
The run printed YTH, three characters. The chatbot included the stop, the classic slice slip. You caught it by running the code, which is the habit this course grades.
Misconception check. Students often think a chatbot's explanation of a slice is safe because it names the right indexes. But a chatbot predicts likely text; it does not run your program, and "1 to 4" is exactly the phrase that hides the half-open rule. The cure is the same as Week 1's: treat every claim about what code prints as a guess, and let the run decide.
In practice (your tools). Ask your approved chatbot what print("hello"[1:4]) and print("hello"[::-1]) display. Write both answers down, then run both lines in your browser runner. Then paste the reading-log program above into Python Tutor at pythontutor.com with its two input() lines replaced by the pinned literals book = "the river book" and pages_today = "30", and step through it one line at a time. When you want the official word, the Python Tutorial's section 3.1.2 on docs.python.org covers indexing and slicing.
Honesty note: this chapter covers only the string tools Week 3 needs. Python has many more ways to work with text, such as methods that change case or split a sentence into words; those come later, in Week 11.
Caveat: the typed-value programs in this chapter assume the user types what the prompt asks for. If someone types letters where a number belongs, int() stops the program with a different error type, which Week 12 teaches you to handle.
Pause and choose one of these to think about before you read on:
- (a) Think of a form you filled in recently that asked for a number, such as a phone number or a quantity. Why might its program keep what you typed as text rather than convert it?
- (b) Think of a label that shortens a longer name, such as a cup label, a bus sign, or a file name. Which slice would produce it, and how many characters does it keep?
Memory hook: ask, convert, build, print — then let the run decide.
Key terms
- input() — The built-in function that shows a prompt, waits for the user to type a line and press Enter, and hands back exactly what was typed as a string. (first used: 1. Ask the keyboard: typed input is always a string)
- prompt — The message input() shows on the screen to tell the user what to type, such as Book title: followed by a space. (first used: 1. Ask the keyboard: typed input is always a string)
- f-string — A string with the letter f right before its opening quote, in which every pair of curly braces holds a name or an expression whose value Python fills in. (first used: 2. Build output with f-strings, not glue)
- concatenation — Joining two strings end to end with the + operator, which works only when both sides are strings. (first used: 2. Build output with f-strings, not glue)
- character — One letter, digit, space, or punctuation mark; a string is a row of characters kept in order. (first used: 3. Pick one character: indexing from 0 and from the end)
- index — A whole number in square brackets after a string that picks out the one character at that position, counting from 0 at the left. (first used: 3. Pick one character: indexing from 0 and from the end)
- zero-based indexing — Numbering the positions in a string starting from 0, so the first character sits at index 0 and the last sits at the length minus 1. (first used: 3. Pick one character: indexing from 0 and from the end)
- negative index — An index below zero that counts back from the end of a string, so an index of minus 1 picks the last character and minus 2 the one before it. (first used: 3. Pick one character: indexing from 0 and from the end)
- slice — A piece cut from a string with square brackets and a colon, as in s[start:stop], which keeps the characters from index start up to, but not including, index stop. (first used: 4. Cut a piece: slices keep the start and drop the stop)
- half-open — Describes a slice that includes its start position and leaves out its stop position, so s[1:4] holds three characters. (first used: 4. Cut a piece: slices keep the start and drop the stop)
- step — The optional third number in a slice, as in s[start:stop:step], which says how many positions to move each time; a step of minus 1 walks backward through the string. (first used: 4. Cut a piece: slices keep the start and drop the stop)
- len() — The built-in function that counts the characters in a string, with spaces and punctuation counted too. (first used: 5. Count characters: the strict index and the forgiving slice)
- IndexError — The error type Python reports when an index points to a position where no character sits, such as index 14 in a string of 14 characters. (first used: 5. Count characters: the strict index and the forgiving slice)
Summary
input()always hands back a string; convert typed digits withint()before arithmetic.- An f-string fills each pair of braces with a value; without the
f, the braces print as they are. - Concatenation with
+joins strings only; a number on one side raises a TypeError. - Indexes start at 0 on the left and at minus 1 on the right.
- A slice keeps its start and drops its stop, so stop minus start is its length.
len()counts every character; the last index is the length minus 1.- An index past the end raises an IndexError; a slice past the end stops quietly.
Check your understanding
Work these before looking at the answers — they are ungraded, and the answers (with reasoning) are at the bottom of the page.
- A gym's check-in program runs
visits = input("Visits this month: ")and thenprint(visits + visits), and the user types 8 (an illustrative example). What does the second line print, and how would you change it to print 16? - A bike rack carries the illustrative code
code = "BIKE42". Predict whatprint(code[0]),print(code[-2:]), andprint(code[1:4])each print. - With
name = "Priya", a program runsprint("Welcome, {name}"). What appears, and what one-character fix makes it greet Priya by name? - With
word = "laptop", predict whatprint(len(word)),print(word[2:10]), andprint(word[6])each do.
Answers (worked reasoning — read after attempting)
- It prints 88. The variable
visitsholds the string "8", so+joins two copies of it into the text 88. To add instead, convert first:print(int(visits) + int(visits))works out 8 + 8 = 16 and prints 16. This is the input-gives-a-string trap in a new setting. code[0]is the first character, B.code[-2:]starts two from the end and runs to the end, so it prints 42 (as text).code[1:4]keeps indexes 1, 2, and 3, which are I, K, and E, so it prints IKE; that is 4 − 1 = 3 characters.- It prints
Welcome, {name}with the braces, because the string has nofin front. Adding thef, as inprint(f"Welcome, {name}"), makes Python fill in the braces, and the line prints Welcome, Priya. len(word)prints 6, because laptop has 6 characters.word[2:10]starts at index 2 and stops quietly at the end, so it prints ptop.word[6]asks for index 6, but the indexes run from 0 to 6 − 1 = 5, so it prints nothing and the last line of its error message names IndexError.
Next up in this module: the Readings & Resources page, the lecture tutorial, the practice set, and the quiz — and next week, the comparison operators and the if statement let a program choose which line runs, often based on what the user typed.
Built with The Course Maker · samples.thecoursemaker.com