Working with Strings in Python

Learn to work with text in Python. Reach any character or section of a string with indexes and slices, loop through text to count, search and build new strings, and see why a string can never be changed in place. Use string methods to change case, clean up input, search, test, split and join text. Finish by formatting output with f-strings: rounded numbers, thousands separators, percentages, US-style dates and times, and neatly aligned columns.

BeginnerLesson 5 of 10 in Python for Beginners: Introduction to Programming

What you will learn

  1. Write string literals, measure and combine strings, and use indexes and slices to reach any character or section of a piece of text.
    • Write string literals and combine strings
      Create strings with quotes, escape sequences and triple quotes, find their length with len(), and combine them with + and *.
    • Pick out single characters by index
      Use positive and negative indexes to read any character of a string, and avoid the off-by-one and empty-string errors that raise IndexError.
    • Slice out parts of a string
      Take substrings with [start:stop] and [start:stop:step], use omitted and negative positions, and predict exactly which characters a slice includes.
  2. Loop through a string to count, search and build text, and work with the fact that a string's characters can never be changed in place.
    • Loop over the characters of a string
      Visit each character with for and while loops, use positions when they matter, and apply the counting, searching and accumulating patterns to text.
    • Build new strings instead of changing old ones
      Explain what it means that strings are immutable, and produce changed text by slicing, concatenating and reassigning.
  3. Call string methods to change case and clean up text, find and count substrings, and check what a string contains before you use it.
    • Change case and clean up text with methods
      Call methods with dot notation to change letter case, remove unwanted characters, replace text and pad strings, and chain several methods together.
    • Search for text inside a string
      Check whether a substring is present, find where it starts, count how often it occurs, and use the positions you find to cut text out.
    • Test and compare strings
      Check what a string starts with, ends with or is made of, validate input before converting it, and predict how Python compares and orders strings.
  4. Break a line of text into words or fields with split(), and combine pieces back into one string with join().
    • Split a string into a list of parts
      Use split() with and without a separator, limit the number of splits, and turn the parts of a line into the values a program needs.
    • Join strings with a separator
      Combine many strings into one with join(), choose the separator, convert non-string items first, and pair split() with join() to reshape text.
  5. Build clear output by inserting values into text with f-strings, formatting numbers, dates and times for readers, and lining up results in columns.
    • Insert values into text with f-strings
      Write f-strings that place the values of variables and expressions into text, and recognize the older format() and % styles in existing code.
    • Format numbers, dates and times for readers
      Add format specifiers to control decimal places, rounding, thousands separators, percentages, signs and zero padding, and build US-style dates and times.
    • Line up output in columns
      Set field widths, alignment and fill characters, shorten long text, and combine these options to print tables and receipts that line up.

Python Strings study guide

5 chapters

1

Create strings and pick out their parts

Text in a program has both content and position. A name may contain a space, a message may contain a line break, and a code may keep its first two letters separate from its number. You can create these strings, combine them, and select exactly the characters you need. Start by distinguishing the way text is written in Python from the value it holds, then use a position picture to make indexes and slices predictable.

1.1 Write string literals and combine strings

A string is a sequence of characters with type str. It can hold a name, a sentence, a code, or no characters at all. Python keeps the characters in order, including spaces and punctuation.

Write the value between matching quotes

Single and double quotes create the same kind of value: 'hello' and "hello" are equal. The outer quotes mark the boundaries; they are not characters in the value. Choose quotes that leave any quotes inside easy to read:

message = "It's late"
reply = 'She said "yes"'
empty = ""

In 'It's late', the apostrophe closes the string too soon, causing a SyntaxError. Double quotes solve this, or you can write 'It\'s late'. Use straight quotes in code.

Store line breaks and backslashes

An escape sequence begins with a backslash. Python reads \n as one newline, \t as one tab, and \\ as one backslash. Escaped quotes, \' and \", put quote characters into text.

text = "a\nb"
print(len(text))  # 3
print(text)

The final call prints a and b on separate lines. The value has three characters: a, a newline, and b. Escapes are processed when Python reads the literal. The shell displays a representation with quotes and escapes where needed; print() displays the characters themselves. For example, "\x41" becomes "A", so the shell need not show the original escape.

Triple quotes let a literal span lines. Each line break inside becomes a newline character:

notice = """Door closed
Use side entrance"""

A raw string has an r before its quotes. In r"C:\new", the backslash and n stay separate, giving six characters. In "C:\new", \n becomes a newline, giving five. Raw literals are useful when backslashes belong in the text.

Measure and combine text

len() counts every character, including spaces: len("Hi there!") is 9, and len("") is 0. More precisely, it counts Unicode code points. len("café") is 4 when é is one code point; len("👍🏽") is 2, even though the emoji looks like one symbol.

Use + to concatenate strings and * to repeat one:

first = "Ada"
last = "Lovelace"
full = first + " " + last  # "Ada Lovelace"
rule = "-" * 10           # ten dashes

Concatenation inserts nothing for you. Without " ", the names become "AdaLovelace". Repeating "ab" zero times gives the empty string.

Decide whether digits are text or numbers

Both operands of string concatenation must be strings. "Age: " + 30 raises TypeError; "Age: " + str(30) gives "Age: 30". Conversely, input() returns text: "3" + "4" gives "34". To add their numerical values, convert them first: int("3") + int("4") gives 7.

Key Takeaways

  • A string stores an ordered sequence of characters; its outer quotes are syntax.
  • is one newline character, while raw literals keep the backslash and following letter separate.
  • len() counts code points, including spaces and punctuation.
  • + joins strings without adding spaces; * repeats a string.
  • Convert text to numbers for arithmetic and numbers to text for concatenation.

1.2 Pick out single characters by index

An index selects one character by its position. Python starts counting at zero, so the position of a character is one less than its place in an ordinary count from the left.

Draw the positions

For word = "Python", each character has a nonnegative index and a negative index:

CharacterPython
From the start012345
From the end-6-5-4-3-2-1
word = "Python"
print(word[0])   # P
print(word[1])   # y
print(word[-1])  # n

The square brackets after the string select the character. The result is a string of length one: Python has no separate character type. You can join selected characters, so word[0] + word[-1] gives "Pn".

For length n, valid indexes run from -n through n - 1 when n > 0. Nonnegative indexes count from the start; negative indexes count from the end. An index of -k selects the same character as n - k; in this six-character word, -2 and 4 both select "o".

Keep the length separate from the last index

len(word) is 6, but word[6] raises IndexError: there is no seventh character. The last character is word[len(word) - 1], or simply word[-1]. Going too far from either end fails; word[-7] also raises IndexError.

An index must be an integer. word[1.0] raises TypeError even though the float has a whole-number value. Use // when computing a middle position:

word = "Pyt"
middle = len(word) // 2  # 1
print(word[middle])      # y

The / operator would produce 1.5, which cannot index a string. For an odd length, len(word) // 2 selects the middle character. For an even length, it selects the right-hand middle character: "Python"[3] is "h".

Build initials from first characters
first = "Grace"
last = "Hopper"
initials = first[0] + last[0]
print(initials)  # GH

Each name contributes its character at index 0. Using first[-1] would contribute "e", the last letter. This method requires each name to have at least one character.

Check blank input before indexing

The empty string has length zero and no valid character index. ""[0] raises IndexError. A length check can keep a program from reading a character that does not exist:

line = input("Comment: ")
if len(line) > 0 and line[0] == "#":
    print("Comment line")

Python evaluates and from left to right. If the length check is false, it skips line[0]. Reversing those two tests would try the unsafe index first. When you only need to know whether a line begins with "#", line.startswith("#") also works on empty input and returns False.

Key Takeaways

  • Index 0 selects the first character; index -1 selects the last.
  • The last nonnegative index is len(text) - 1.
  • Indexing returns a one-character string and raises IndexError for a missing position.
  • Use an integer index and check for empty input before selecting a character.

1.3 Slice out parts of a string

A slice selects a run of characters and returns it as a string. It lets you take a prefix, remove an ending, or separate fields that occupy fixed positions.

Start is included; stop is excluded

Write text[start:stop]. With s = "Monty Python", s[0:5] gives "Monty", and s[6:12] gives "Python". The space is at index 5, so the second slice begins at 6.

Picture the slice numbers as gaps. Gap 0 is before the first character, and gap 5 is after the first five. Taking everything between them gives five characters. For 0 <= start <= stop <= len(text), the length is stop - start.

word = "Monty"
print(word[0:4])  # Mont
print(word[0:5])  # Monty

The stop position is the first position left out. Adding one to the desired last index includes that last character.

Leave out a boundary
SliceMeaningResult for s
s[:5]Start through position 4"Monty"
s[6:]Position 6 through the end"Python"
s[:]Whole string"Monty Python"
s[-6:]Last six characters"Python"
s[:-1]Everything except the last character"Monty Pytho"

At any split position k, s[:k] + s[k:] gives back s. The slices meet at the same gap, with no missing or repeated character.

Slice boundaries beyond the ends are clipped. "cat"[1:100] is "at"; "cat"[5:] is "". For a forward slice, a start at or after the stop gives an empty string, as in s[4:2]. Unlike a single-character index, an out-of-range slice does not raise IndexError.

Choose a step

The third slot in text[start:stop:step] sets how far to move between selected positions:

letters = "abcdefgh"
print(letters[::2])   # aceg
print(letters[1::2])  # bdfh
print(letters[::-1])  # hgfedcba

A negative step moves backward. With both boundaries omitted, [::-1] starts at the last character and visits every character in reverse order. A step of zero raises ValueError. The direction must agree with the boundaries: the “start at or after stop” empty-result rule above is for a positive step.

Apply slices to a fixed layout
d = "2026-07-04"
year = d[:4]
month = d[5:7]
day = d[8:10]
print(month + "/" + day + "/" + year)  # 07/04/2026

The positions work because this layout always uses four digits for the year and two for the month and day. Text with varying field lengths needs a search or a split.

Reversal also gives a palindrome test: word == word[::-1]. "level" passes, but "Level" fails because case counts. Assign clean = word.lower() and test clean == clean[::-1] to ignore case.

Key Takeaways

  • A slice includes its start and excludes its stop.
  • Omitted boundaries and negative positions make prefixes and endings easy to select.
  • Out-of-range slice boundaries are clipped; a zero step raises ValueError.
  • A negative step moves backward; [::-1] reverses the whole string.
  • Fixed-position slices depend on a consistent text layout.
2

Process strings character by character

A loop can inspect each character, keep a running count, stop at the first match, or build a new message. The same small patterns work for many text tasks: counting vowels, finding a digit, or hiding selected letters. Strings also have a fixed value once created. Following a loop one pass at a time will show how a program can produce changed text while the original string stays intact, and why assigning a variable is different from editing a character.

2.1 Loop over the characters of a string

Use a loop when a decision must be made about each character. The loop can count matches, use their positions, stop at the first match, or collect the characters that belong in a result.

Visit characters directly
for ch in "hi!":
    print(ch)

The body runs three times, with ch equal to "h", "i", and "!" in turn. The empty string runs the body zero times. A direct character loop needs no index when you only use the current character.

For a count, initialize the counter before the loop and increase it only when the test passes:

text = "Programming in Python"
count = 0
for ch in text.lower():
    if ch in "aeiou":
        count += 1
print(count)  # 5

Lowercasing makes uppercase vowels match too. The test string defines the vowels being counted; it does not include y. Resetting count inside the loop would lose the total from earlier passes.

Use positions when neighboring characters matter

range(len(text)) supplies the indexes from zero through the last valid index. For a task that needs both the position and character, enumerate(text) supplies them together:

for i, ch in enumerate("abc"):
    print(i, ch)

This prints 0 a, then 1 b, then 2 c. The two loop variables receive the index and character from each pair.

To compare neighbors, the last index cannot be the current position because it has no next character:

text = "bookkeeper"
pairs = 0
for i in range(len(text) - 1):
    if text[i] == text[i + 1]:
        pairs += 1
print(pairs)  # 3

The matches are oo, kk, and ee. With range(len(text)), the last pass would try text[len(text)] and raise IndexError.

Manage a position with while
i = 0
while i < len(text):
    print(text[i])
    i += 1

The test is strictly <: position len(text) is past the end. The increment moves the loop toward stopping; leaving it out keeps reading the same character forever on nonempty text. For a backward walk, start at len(text) - 1, continue while i >= 0, and subtract one on each pass.

Search or collect

For the first digit in "Room 42B", stop once a match has been used:

for ch in "Room 42B":
    if ch.isdigit():
        print(ch)  # 4
        break

Without break, both digits would print. For a simple presence test, "4" in text already answers yes or no.

To collect text, start with result = "" and add each wanted character. For "a b c", adding only when ch != " " builds "abc". Assigning ch = ch.upper() inside a loop changes only the loop variable; it does not change the characters stored in text.

Key Takeaways

  • A direct for loop visits each character in order.
  • Initialize counters and accumulators before the loop.
  • enumerate() supplies each index with its character.
  • Stop one position early when reading text[i + 1].
  • A while loop needs a safe boundary and a position update.
  • break stops a search at its first match.

2.2 Build new strings instead of changing old ones

Strings are immutable: their characters cannot be changed after the string exists. A program that seems to edit text is building another string and choosing which variable will refer to it.

Read a character, but do not assign to it
name = "Jane"
name[0] = "D"  # TypeError

The index can read "J", but it cannot be the target of an assignment. del name[0] also raises TypeError. To get "Dane", combine the desired first character with the unchanged ending:

name = "Jane"
name = "D" + name[1:]
print(name)  # Dane

Python first evaluates the right side, producing a new string. It then makes name refer to that result.

Replace or insert at a known position

For a valid nonnegative index i, these expressions use different right-hand slices:

TaskExpression
Replace character at itext[:i] + new + text[i + 1:]
Insert before character at itext[:i] + new + text[i:]

Replacement skips the old character; insertion keeps it. With text = "cat", i = 1, and new = "X", replacement gives "cXt", while insertion gives "cXat".

Convert a negative index to its nonnegative equivalent before using this replacement pattern. For the last character of "cat", i = len(text) - 1 is 2. If you put -1 directly into text[i + 1:], it becomes text[0:], which appends the entire old string and gives "caXcat".

Retain a method's result

Transformation methods follow the same immutable rule:

msg = "hello"
msg.upper()
print(msg)       # hello
msg = msg.upper()
print(msg)       # HELLO

The first call computes a result that the program discards. The assignment keeps the second result. String methods never change the original string, but their return types differ: upper() returns a string, find() an integer, and isdigit() a Boolean.

Track two names for one value

After a = "cat" and b = a, both variables refer to "cat". Running a = a + "s" gives a the new value "cats"; b still refers to "cat". No character in the shared old string changed. a += "s" performs the same kind of reassignment for a string.

Build a changed value in a loop
word = "secret"
masked = ""
for ch in word:
    if ch in "aeiou":
        masked += "*"
    else:
        masked += ch
print(masked)  # s*cr*t
print(word)    # secret

Each pass extends masked with one chosen character. Putting each character at the front instead, with result = ch + result, reverses text: the passes over "drawer" build "d", "rd", "ard", "ward", "eward", and "reward".

Repeated concatenation is convenient for short examples. When pieces already exist in a list, "".join(pieces) builds one result directly and can also place a separator between them.

Key Takeaways

  • A string cannot be changed by item assignment or deletion.
  • Replacement and insertion build new strings from slices.
  • Keep a transformation result by assigning it.
  • Reassigning one variable leaves other variables pointing to the old value.
  • An accumulator builds a new string one chosen piece at a time.
3

Transform, search and test text with string methods

String methods let you ask useful questions about text and produce cleaned versions of it. A program may need to accept extra spaces in a reply, find a separator, or check that a quantity can be converted to a number. Choose a method by the result you need: changed text, a position, a count, or a Boolean test. Pay attention to exact matching, the value returned when a search fails, and the difference between text order and numerical order.

3.1 Change case and clean up text with methods

A method is a function attached to a value. String methods handle common jobs such as changing case, trimming input, and replacing text. Each call returns a result and leaves the original string unchanged.

Call a method with dot notation

Write value.method(arguments), as in "hello".upper(). Parentheses make the call happen. name.upper without parentheses refers to the method itself; it does not produce uppercase text. Writing upper(name) does not find a standalone function named upper. Use dir("") to list string methods and help(str.upper) to read about one.

Choose a case operation
MethodResult for the example
"Hello".upper()"HELLO"
"Hello".lower()"hello"
"Hello".swapcase()"hELLO"
"the old man".title()"The Old Man"
"hELLO wORLD".capitalize()"Hello world"

capitalize() changes the first character and lowercases the rest; title() starts words again after nonletter characters. This makes "they're".title() become "They'Re", so automatic title casing can need checking.

For comparisons without case differences, casefold() handles more cases across languages than lower(). "Straße".lower() is "straße", while "Straße".casefold() is "strasse". Case-fold both strings before comparing them.

Clean the ends of text

strip() removes leading and trailing whitespace, including spaces, tabs, and newlines. It preserves internal spacing: " New York \n".strip() is "New York". lstrip() cleans only the left end; rstrip() cleans only the right.

With an argument, stripping removes any of those characters repeatedly from the ends. It does not remove an exact word:

print("...Wow!!!".strip(".!"))          # Wow
print("report.txt".rstrip(".txt"))     # repor
print("report.txt".removesuffix(".txt"))  # report

The final t in report also belongs to the stripping character set, so it disappears. removeprefix() and removesuffix() remove exact text at an end; they are available in Python 3.9 and later.

Replace matches and chain changes

replace(old, new) replaces every exact match. A third argument limits how many matches change: "a-b-c".replace("-", "", 1) gives "ab-c". An empty replacement deletes matches. Case counts, so "Cat cat".replace("cat", "dog") gives "Cat dog".

answer = "  YES \n"
answer = answer.strip().lower()
print(answer == "yes")  # True

The calls run left to right: strip() returns "YES", then lower() returns "yes". A chain works when the next method fits the previous result's type. A search result is an integer, so it does not support string cleanup methods.

For padding, "7".zfill(3) gives "007", "Total".ljust(8) adds three spaces on the right, and "Hi".center(8, "*") gives "***Hi***". rjust() pads on the left. These widths are minimums; longer text is kept in full.

Key Takeaways

  • Use dot notation and parentheses to call a string method.
  • Case operations have different jobs; casefold() supports comparisons across languages.
  • strip(chars) removes a set of end characters; exact affixes need removeprefix() or removesuffix().
  • replace() matches exact text and can limit the number of changes.
  • Transformation chains run left to right on each returned string.
  • Padding adds characters up to a minimum width.

3.2 Search for text inside a string

Searching can answer three different questions: whether text occurs, where it starts, and how often it occurs. Choose the result that fits the decision your program needs to make.

Choose a search result
ToolResultWhen no match exists
sub in textPresence as True or FalseFalse
text.find(sub)First starting index-1
text.rfind(sub)Last starting index-1
text.index(sub)First starting indexRaises ValueError
text.count(sub)Number of nonoverlapping matches0

A substring is a consecutive run of characters. "py" in "happy" is True, but "hpy" in "happy" is False. Matching is case-sensitive: "Py" in "python" is False. not in reverses the presence test. The empty string occurs in every string.

Find the right occurrence
text = "banana"
print(text.find("an"))     # 1
print(text.find("an", 2))  # 3
print(text.rfind("an"))    # 3

The optional start position skips earlier candidates. The returned index still counts from the beginning of the whole string. index() returns the same position when a match exists, but its missing-match error makes it useful when absence signals an unexpected problem.

Check a position before slicing
email = "maria.lopez@example.org"
at = email.find("@")
if at != -1:
    user = email[:at]
    domain = email[at + 1:]
    print(user)    # maria.lopez
    print(domain)  # example.org

The search returns 11. The first slice stops before @; the second starts one character after it. If the marker were absent, at would be -1. Using that as a slice boundary would silently select text near the end, so handle the missing marker before extracting parts.

Do not use if text.find("x"): as a presence test. A match at index 0 counts as false in a condition, while the missing-result value -1 counts as true. Use if "x" in text: or compare the position explicitly with -1.

Search from a known marker

For line = "Order #4521 shipped", the number follows # and ends at the next space:

start = line.find("#") + 1
end = line.find(" ", start)
number = line[start:end]
print(number)  # 4521

Here both markers exist. Starting the second search at start skips the earlier space after Order. If markers may be missing, check each raw search result before adding one or slicing; adding one to -1 would hide the failed search by turning it into 0.

Count whole matches

"banana".count("a") is 3, and "banana".count("ana") is 1. The two possible ana matches overlap, so count() does not count both. Similarly, "aaaa".count("aa") is 2.

To ignore case, search a converted version, such as "python" in sentence.lower(). The search still matches exactly within that version. Counts and presence tests can use the converted string directly; an index belongs to the particular string searched.

Key Takeaways

  • Use in for presence, a search method for position, and count() for frequency.
  • find() and rfind() return -1 when text is missing; index() raises ValueError.
  • Check a search result before using it as an index or slice boundary.
  • A start argument skips earlier matches while keeping whole-string indexes.
  • count() counts nonoverlapping matches.

3.3 Test and compare strings

String tests return Booleans that can guide a condition. They help you accept input that matches a rule and compare text in a consistent form.

Test the ends or the characters

startswith() and endswith() test exact text at the ends. A tuple lets one test accept several endings: name.endswith((".jpg", ".png")). Uppercase "photo.PNG" fails that test unless you lowercase it first.

TestTrue when the nonempty string has…
isalpha()Only letters
isalnum()Only letters or digits
isdigit()Only Unicode digit characters
isdecimal()Only decimal digit characters
isspace()Only whitespace

All five return False for "". Letters need not be English: "café".isalpha() is True. The space in "hello world" makes isalpha() false.

isupper() and islower() look at cased characters and require at least one. "ABC1".isupper() is True; the digit does not spoil uppercase letters. "123" has no cased characters, so both tests are false.

Validate before conversion

A digit test does not describe every number Python can read. "-5".isdigit(), "3.5".isdigit(), and " 42".isdigit() are false because a sign, point, or space is not a digit. Also, "²".isdigit() is true even though int("²") fails. isdecimal() rejects that superscript and suits a plain nonnegative whole-number entry.

text = input("Tickets: ").strip()
if text.isdecimal() and int(text) > 0:
    print("Accepted")
else:
    print("Enter a positive whole number")

The string test runs first. When it is false, and skips the conversion, protecting blank or nonnumeric input. " 12 " becomes "12" and passes; "0" converts safely but fails the positive-value test. This rule deliberately rejects signed or decimal-point entries.

A username rule can combine length and character checks: 3 <= len(name) <= 12 and name.isalnum(). "ada99" passes, "ada 99" fails the character test, and "ad" fails the length test.

Compare cleaned text

Equality requires the same characters in the same order. "Yes" == "yes" and "yes " == "yes" are false. For answers where case and outer whitespace should be ignored, compare typed.strip().casefold() with expected.strip().casefold().

Ordering works character by character. The first differing Unicode code point decides. ord("A") is 65, ord("Z") is 90, and ord("a") is 97; chr(97) gives "a". Thus "Zebra" < "apple" is true. When one string is a prefix of the other, the shorter one comes first: "app" < "apple".

Digit strings also use character order: "10" < "9" is true because "1" comes before "9". Convert to numbers when comparing quantities. Accented letters need care too: ord("é") is 233, so "école" > "zoo" is true. This built-in order follows code points, not a language's dictionary order.

Key Takeaways

  • String tests return Booleans; character tests also check that the string is nonempty.
  • isdecimal() is stricter than isdigit() for input intended for int().
  • Use a character test before a guarded numerical conversion.
  • Clean both strings consistently when case and outer spaces should not matter.
  • String ordering uses the first different code point; numeric order needs numeric values.
4

Split text into parts and join parts into text

A line of text often holds several useful pieces: words in a message, fields in a record, or parts of a code. Splitting turns that line into an ordered collection you can inspect, count, and convert. Joining builds one string from pieces with a separator you choose. The separator rules determine whether empty fields and original spacing survive, so the choice matters when you clean text or need to reconstruct it exactly.

4.1 Split a string into a list of parts

split() turns one string into a list of strings. A list is an ordered collection written in square brackets. You can read an item by index, loop over the items, or count them with len().

Choose whitespace or an exact separator

Without an argument, split() treats a run of whitespace as one boundary and ignores whitespace at both ends:

words = "  the quick  brown fox ".split()
print(words)       # ['the', 'quick', 'brown', 'fox']
print(len(words))  # 4
print(words[0])    # the

With an explicit separator, each exact occurrence makes a cut. Consecutive separators preserve an empty field:

fields = "red,green,,blue".split(",")
# ["red", "green", "", "blue"]

The empty third item may represent a value that was left blank. It still counts as an item in the list.

ExpressionResult
"a b".split()["a", "b"]
"a b".split(" ")["a", "", "b"]
"a,b".split(", ")["a,b"]

A separator can contain several characters, but all of them must match. If no separator occurs, the result holds the whole original string as one item. Splitting on comma-space therefore differs from splitting on a comma.

Limit how much text is split

The second argument, maxsplit, limits the number of cuts, not the number of resulting items:

print("key=value=more".split("=", 1))
# ["key", "value=more"]
print("archive.tar.gz".rsplit(".", 1))
# ["archive.tar", "gz"]

split() starts from the left; rsplit() starts from the right. One right-hand split separates the last file extension without cutting earlier periods.

Read fields and convert quantities
line = "Lovelace,Ada,1815"
parts = line.split(",")
if len(parts) == 3:
    last = parts[0]
    first = parts[1]
    year = int(parts[2])
    print(f"{first} {last} was born in {year}.")

The output is "Ada Lovelace was born in 1815.". The length check prevents a missing item from causing IndexError. It does not check that the year is numeric; that needs a separate input rule when the data may be invalid.

Every split part starts as a string. To total "3 14 15", initialize total = 0, loop over line.split(), and add int(part). The result is 32; concatenating the unconverted pieces would join digits.

An explicit separator keeps surrounding spaces. "a, b".split(",") gives ["a", " b"]. Call strip() on each part if those spaces are unwanted.

Recognize two related results

splitlines() separates line breaks: "line one\nline two".splitlines() gives two strings. partition("=") always returns a three-part tuple: the text before the first separator, the separator, and the text after. "user=ada".partition("=") gives ("user", "=", "ada"); with "user", it gives ("user", "", "").

Key Takeaways

  • split() returns an ordered list of strings.
  • Whitespace splitting collapses runs; explicit separators preserve empty fields.
  • maxsplit limits cuts, and rsplit() starts at the right.
  • Check field counts before indexing and convert numeric fields before arithmetic.
  • splitlines() separates lines; partition() returns before, separator, and after.

4.2 Join strings with a separator

join() builds one string from a sequence of strings. The string before the dot supplies the separator, which appears between adjacent items.

Put the separator first
colors = ["red", "green", "blue"]
text = ", ".join(colors)
print(text)  # red, green, blue

Read this as “use comma-space to join the colors.” There is no separator before the first item or after the last. You can change the output layout by changing only the separator:

ExpressionResult
"".join(["a", "b", "c"])"abc"
"-".join(["a", "b", "c"])"a-b-c"
"\n".join(["a", "b", "c"])One item on each line

join() belongs to the separator string. Writing ["a", "b"].join(",") raises AttributeError because the list has no join method. A single call also adapts to the number of pieces; you do not need to write a new chain of + operations for each different list length.

Convert nonstring pieces first

All pieces must already be strings. ", ".join([1, 2, 3]) raises TypeError. map(str, items) applies str() to each item, so this works:

items = [1, 2, 3]
text = " ".join(map(str, items))
print(text)  # 1 2 3

The str passed to map() is the conversion function. join() receives the converted pieces and returns one string.

A string is itself a sequence of one-character strings, so " ".join("ABC") gives "A B C". This can be useful, but passing one word when you meant a list of words puts separators between its characters.

Reshape spacing and separators
text = "too   many    spaces"
cleaned = " ".join(text.split())
print(cleaned)  # too many spaces

First, whitespace splitting produces the three words. Joining them with one space chooses a consistent gap and leaves no outer spaces. Original spacing is lost at the split step.

With an explicit separator, the empty fields preserve enough information to rebuild the exact text. If s = "a,,b,", then s.split(",") gives ["a", "", "b", ""], and ",".join(...) gives "a,,b," again. The separator must be the same for that exact reconstruction.

Changing the separator changes the layout: "-".join("2026/07/04".split("/")) gives "2026-07-04". Here replace("/", "-") is also a direct solution.

Collect a small result from words

For an acronym, split "portable network graphics", start acronym = "", and add word[0].upper() for each word. Whitespace splitting supplies nonempty words, so their first characters exist. This builds "PNG". If the letters are already in a list, ".".join(["P", "N", "G"]) builds "P.N.G" with no trailing period.

Key Takeaways

  • Call join() on the separator, passing the pieces as its argument.
  • Separators appear only between pieces, and every piece must be a string.
  • Splitting on whitespace and joining with one space standardizes spacing.
  • Joining with the same explicit separator can reconstruct text including empty fields.
5

Format output with f-strings

Useful output combines a correct value with a readable layout. An f-string places values and expressions directly inside text, then lets you choose how each field looks: decimal places, grouping, signs, dates, or aligned columns. Keep the calculation and the display separate. A field can show two decimal places or a shortened name while the original variable retains its full value, ready for later calculations or a different display.

5.1 Insert values into text with f-strings

An f-string is a string literal with f or F before its opening quote. Inside it, braces hold expressions whose values are inserted into the text.

Insert variables and expressions
name = "Ada"
age = 36
message = f"{name} is {age} years old."
print(message)  # Ada is 36 years old.

Numbers become text automatically inside a field. The same message could use concatenation and str(age), but the f-string keeps the final layout visible in one place.

The braces can hold arithmetic, method calls, or function calls:

price = 4.5
qty = 3
print(f"Cost: {price * qty}")  # Cost: 13.5
print(f"Name: {name.upper()}")  # Name: ADA
word = "Python"
print(f"{len(word)} letters")  # 6 letters

Python evaluates each expression when the line runs. A saved string does not stay connected to the variables used to build it. If qty changes after message has been built, that string keeps its existing characters.

Distinguish ordinary text from fields

Without the prefix, "Hello {name}" is ordinary text and keeps its braces. The missing f is a common reason a program prints the variable name instead of its value. With the prefix, a name that has not been assigned raises NameError when the expression runs.

To show a literal brace, double it:

x = 5
print(f"{{x}} = {x}")  # {x} = 5

The doubled braces supply the literal text {x}. The single pair around the final x supplies its value.

Keep quoted expressions easy to read

Use the other kind of quote inside a field:

print(f"Shout: {'hi'.upper()}")  # Shout: HI

This style works in all Python versions with f-strings, which began in 3.6. Python 3.12 and later also allow reusing the outer quote type inside the field. Escape sequences still work in f-strings: f"Name: {name}\nAge: {age}" prints on two lines.

For a quick debugging display, Python 3.8 and later accept = after an expression. With x = 5, f"{x=}" gives "x=5"; with total = 12, f"{total = }" gives "total = 12". Spaces typed around the expression and equals sign appear in the display.

Read older formatting styles

Existing Python code may build the same text in other ways:

StyleExampleResult
F-stringf"{name} is {age}""Ada is 36"
String method"{} is {}".format(name, age)"Ada is 36"
Percent formatting"%s is %d" % (name, age)"Ada is 36"

str.format() fills brace fields from its arguments. Numbered fields can reuse an argument: "{0} {1} {0}".format("a", "b") gives "a b a". In percent formatting, %s inserts text and %d a whole number. Recognizing those fields helps you read a program even when it was written before f-strings were common.

Key Takeaways

  • An f-string needs an f prefix and braces around each expression.
  • Fields are evaluated when the f-string runs; saved text does not update later.
  • Double braces display literal braces.
  • str.format() and percent formatting are older ways to insert values.

5.2 Format numbers, dates and times for readers

A format specifier controls how a value is displayed. Put a colon after the expression, then the instructions: f"{value:spec}". Formatting returns text and leaves the original numerical value unchanged.

Set decimal places and understand rounding

.Nf shows exactly N digits after the decimal point. f"{3.14159:.2f}" gives "3.14", f"{2/3:.3f}" gives "0.667", and f"{5:.2f}" gives "5.00". .0f shows no decimal point: f"{7.6:.0f}" gives "8".

Rounding uses the value actually stored. Most decimal fractions are very close binary approximations. The float 2.675 is slightly below that exact decimal, so f"{2.675:.2f}" gives "2.67". Exactly halfway values round to the even final digit: 0.125 displays as "0.12", while 0.375 displays as "0.38" at two decimal places. f"{2.5:.0f}" gives "2". Programs needing exact money calculations often store whole cents as integers.

Add grouping and percentages
SpecifierExample result
f"{1234567:,}""1,234,567"
f"{1234567:_}""1_234_567"
f"{1234567.891:,.2f}""1,234,567.89"
f"{0.256:.1%}""25.6%"

A comma groups thousands; the point introduces decimal precision. For a dollar amount, keep the dollar sign outside the field: with amount = 1250.5, f"${amount:,.2f}" gives "$1,250.50".

The % type multiplies by 100 and adds %. Use a fraction such as 0.256 to display 25.6%. If you supply 25.6, the displayed percentage is multiplied again. Without an explicit precision, % shows six decimal places.

Format whole numbers and date parts

d is for integers. f"{42:d}" works, but f"{3.0:d}" raises ValueError because a float is not an integer. A leading zero before a width adds zero padding; a plus sign requests a visible sign:

print(f"{7:03d}")   # 007
print(f"{5:+d}")    # +5
print(f"{-5:+d}")   # -5

For month 7, day 4, and year 2026, f"{month:02d}/{day:02d}/{year}" builds "07/04/2026". For hour 9 and minute 5, f"{hour}:{minute:02d}" builds "9:05". The zero padding prevents a one-digit minute from appearing as "9:5".

Combine instructions in order

The order is fill, alignment, sign, zero, width, grouping, precision, type. You can omit unneeded parts. f"{12345.678:>12,.2f}" uses right alignment, width 12, comma grouping, and two decimals, giving " 12,345.68".

Precision can come from another variable: with places = 3, f"{3.14159:.{places}f}" gives "3.142". The same specifiers work in format(value, spec) and str.format() fields. Keep the original number for calculations; round(value, 2) returns a rounded number when that is what the calculation needs.

Key Takeaways

  • A colon introduces display instructions; the stored value does not change.
  • Fixed-point precision chooses decimal places, and rounding follows the stored value.
  • A comma groups thousands; % scales a fraction by 100.
  • d requires an integer; zero padding keeps date and time parts readable.
  • Keep numbers for arithmetic and format at display time.

5.3 Line up output in columns

A field width reserves a minimum number of character positions for a value. Combining widths makes short tables and receipts readable in a terminal.

Choose width and alignment

Strings align left by default, and numbers align right. f"{'cat':6}" gives "cat ", while f"{42:6}" gives " 42". Use an alignment character to choose explicitly:

CharacterMeaningExample
<Leftf"{'hi':<6}" gives "hi "
>Rightf"{'hi':>6}" gives " hi"
^Centerf"{'hi':^6}" gives " hi "

When centering leaves an odd number of spaces, f-string alignment puts the extra space on the right: f"{'hi':^7}" gives " hi ".

Width is a minimum. f"{'elephant':4}" still gives "elephant"; it does not cut the word. A long entry can therefore push later columns out of line.

Add a fill character or limit text

A fill character goes immediately before alignment. f"{'hi':*^10}" gives "****hi****", and f"{7:0>3}" gives "007". Fill needs an alignment character. f"{'':-^20}" fills an empty field with twenty dashes.

String precision limits the number of characters shown:

place = "Washington"
print(f"{place:.4}")      # Wash
print(f"|{place:10.4}|")  # |Wash      |

The precision first limits the displayed text to four characters; the width then pads it to ten. Use matching width and precision when text must stay inside a fixed column. The original place is still "Washington".

Build one receipt row
item = "Apples"
qty = 3
price = 4.50
row = f"{item:<8}{qty:>4}{qty * price:>9.2f}"
print(row)

The result is "Apples 3 13.50". The item field has six letters and two spaces. The quantity field adds three spaces before 3. The cost field adds four spaces before 13.50, which has five characters. Together the fields occupy 21 characters.

Reuse those widths for bread (1 at 2.25) and coffee (2 at 11.00). Their rows are "Bread 1 2.25" and "Coffee 2 22.00". A total row can combine the first two fields:

print(f"{'Total':<12}{37.75:>9.2f}")
# "Total           37.75"

The cost field begins at the same position and has the same decimal precision, so the amounts align.

Match the layout to its display

Choose widths that leave room for the longest entries and spacing, or shorten text deliberately. A variable can supply a width: with w = 10, f"{name:<{w}}" pads name to ten characters.

Character-based columns need a monospaced font such as a terminal uses. For plain padding outside an f-string, ljust() and rjust() behave like < and >. center() and ^ both center text but can split odd padding differently: "hi".center(7) gives " hi ", while f"{'hi':^7}" gives " hi ".

Key Takeaways

  • Width sets a minimum; alignment decides where padding goes.
  • Fill precedes alignment, and string precision limits displayed characters.
  • Use the same field widths and decimal precision on every row.
  • Choose a monospaced display for character-based columns.
  • center() and f-string centering can place odd padding differently.

Python Strings examples

5 Walkthroughs

1

Take a code apart one character at a time

14 steps
Create a label, read positions, and extract or reverse selected sections.
  1. 1
    IntroductionRead a storage label

    A storage label contains letters, a hyphen, and digits: "Box-482". This is a string, and each character has an index. A program may need the first letter, the final digit, or the whole number section (a slice).

    You will build the label, draw its positions, and select its parts. Follow the exact characters at each step; a space or separator affects positions just as a letter does.

  2. 2
    ExplanationSeparate syntax from stored text

    A string is an ordered sequence of characters. The outer quotes tell Python where a literal starts and ends; they do not enter its value.

    label = "Box-482"
    print(len(label))  # 7
    

    The hyphen is one of the seven characters. Single quotes could mark the same value. You can also store empty text with "", which has length zero.

  3. 3
    ExampleBuild the label from pieces

    Start with the word and a numerical code:

    kind = "Box"
    number = 482
    label = kind + "-" + str(number)
    

    str(number) makes "482", then the two concatenations build "Box-482". The hyphen appears because it is a supplied piece. Omitting str() would try to concatenate a string and an integer, which raises TypeError.

  4. 4
    ChallengeCount the value with an escape

    A short notice is stored as notice = "A\nB!". What is its length, and how many lines does print(notice) display?

    ---reveal---

    The length is 4: A, one newline, B, and !. Printing displays two lines, with A on the first and B! on the second. The escape is processed when the literal is read; printing reveals the newline already in its value.

  5. 5
    AnalogyPut a number on each position

    Think of the label as seven numbered spaces in a row. Numbering begins at zero:

    Character: B o x - 4 8 2
    Index:     0 1 2 3 4 5 6
    

    label[0] gives "B", and label[4] gives "4". The result is a one-character string, even when it looks like a number. Position 7 would be the eighth space, which does not exist in this label.

  6. 6
    ExplanationCount back from the final character

    Negative indexes use the end as their reference point. For "Box-482", label[-1] is "2" and label[-3] is "4".

    The nonnegative equivalent of -3 is len(label) - 3, or 4. Both select the same character. There is no negative zero position at the end: -0 is simply 0, so it still selects the first character.

  7. 7
    ChallengeSelect a character without running code

    For code = "Tin-739", what is code[-2]? Would code[len(code)] select the final character?

    ---reveal---

    code[-2] is "3", the character just before the final 9. code[len(code)] raises IndexError: length seven means indexes zero through six. The last-character expression is code[len(code) - 1], or code[-1].

  8. 8
    TipGuard a character read

    A blank input has no character at index zero. Put the length check before the character read:

    if len(label) > 0 and label[0] == "B":
        print("Begins with B")
    

    When the first test is false, and skips the second one. This order matters: putting label[0] first would already fail on blank input before Python could reach the length check.

  9. 9
    ExplanationSelect the entire number section

    A slice includes its start and excludes its stop:

    label = "Box-482"
    number_text = label[4:7]
    print(number_text)  # 482
    

    Positions 4, 5, and 6 supply the digits. Stop 7 is the boundary after the last character. Since the selection runs to the end, label[4:] gives the same result. No conversion happens; the slice is still text.

  10. 10
    ExampleMake the two slices meet

    The left section ends at the boundary where the number section starts:

    left = label[:4]   # "Box-"
    right = label[4:]  # "482"
    print(left + right)  # Box-482
    

    The common boundary 4 makes the pieces meet without a gap or an overlap. This is why s[:k] + s[k:] rebuilds a string. Using label[:3] would leave the hyphen out of the reconstructed result.

  11. 11
    Key InsightA slice boundary can pass the end

    Compare label[99] with label[4:99]. The single index raises IndexError, but the slice gives "482".

    A slice clips a boundary beyond the string to its available end. label[99:] therefore gives empty text. This is useful for taking up to a certain amount of text, but it also means an incorrect slice can quietly return fewer characters than you expected.

  12. 12
    ExampleReverse only the selected digits

    First extract the digits, then reverse that new string:

    digits = label[4:]
    backward = digits[::-1]
    print(backward)  # 284
    

    A negative step walks backward. With both boundaries omitted, the slice visits all characters from last to first. A positive step of two would skip alternate positions instead. A zero step is invalid and raises ValueError.

  13. 13
    ChallengeBuild a changed label

    For label = "Jar-916", what is label[:4] + label[4:][::-1]? Explain which section keeps its order.

    ---reveal---

    The result is "Jar-619". The first slice keeps "Jar-" unchanged. The second first selects "916", then [::-1] reverses just those digits to "619". Concatenation places the two results together without adding another separator.

  14. 14
    RecapKeep positions and boundaries distinct

    Use an index for one character and a slice for a section. Positions begin at zero; negative indexes count from the end. A slice leaves out its stop, and its step controls direction and spacing.

    Track the stored characters first, then evaluate each selection before combining the results.

2

Build a masked code with a loop

12 steps
Trace counters and string accumulation, then explain why the original text stays unchanged.

Save this lesson to follow every Walkthrough step by step.

  1. 1
    IntroductionKeep digits and hide letters
  2. 2
    ExplanationSet up the running results
  3. 3
    ExampleMake one decision for each character
  4. 4
    ExampleFollow the remaining passes
  5. 5
    ChallengeTrace a different input
  6. 6
    ConnectionAdd positions only when needed
  7. 7
    TipLeave room for a next character
  8. 8
    Key InsightThe old string has not been edited
  9. 9
    ExampleKeep another name for the old value
  10. 10
    ExampleReplace one position with slices
  11. 11
    ChallengeTrace both the value and its saved copy
  12. 12
    RecapTrack each variable through the loop
3

Read and validate a tagged message

16 steps
Clean user text, locate markers, and apply input tests before numerical conversion.

Save this lesson to follow every Walkthrough step by step.

  1. 1
    IntroductionProcess a short request
  2. 2
    ExampleClean the outer whitespace
  3. 3
    ExplanationCall and chain methods
  4. 4
    ChallengeChoose an exact ending operation
  5. 5
    ConnectionCompare text with case folding
  6. 6
    ExplanationAsk whether, where, or how often
  7. 7
    ExampleLocate the beginning of the name
  8. 8
    ExampleFind the end after the beginning
  9. 9
    TipDo not treat a position as presence
  10. 10
    ChallengeExtract a field between markers
  11. 11
    ExampleTake the seat text out
  12. 12
    ExplanationTest before converting
  13. 13
    ChallengeApply the same input rule
  14. 14
    Key InsightA text comparison does not compare quantities
  15. 15
    ChallengeHandle a cleaned field and a failed search
  16. 16
    RecapUse each result for its intended job
4

Turn a record into fields and readable text

12 steps
Split a small record, convert its quantities, and join pieces using deliberate separator rules.

Save this lesson to follow every Walkthrough step by step.

  1. 1
    IntroductionRead a simple record
  2. 2
    ExplanationSplit at an exact separator
  3. 3
    ExampleCheck the fields before reading them
  4. 4
    ExampleCalculate using converted values
  5. 5
    ChallengePreserve a missing value
  6. 6
    Key InsightWhitespace splitting chooses different pieces
  7. 7
    TipStop after the cut you need
  8. 8
    ExampleJoin display pieces with a separator
  9. 9
    ChallengePredict a join with empty pieces
  10. 10
    ConnectionChoose cleanup or exact reconstruction
  11. 11
    ChallengeRepair a record display
  12. 12
    RecapFollow the types through the record
5

Format a small receipt

16 steps
Build f-strings, choose number formats, and align a receipt row without changing the underlying data.

Save this lesson to follow every Walkthrough step by step.

  1. 1
    IntroductionGive a calculation a readable layout
  2. 2
    ExampleInsert the line cost
  3. 3
    ChallengeNotice when the expression runs
  4. 4
    TipKeep field syntax visible
  5. 5
    ExplanationChoose two decimal places
  6. 6
    Key InsightRound the value that is actually stored
  7. 7
    ExampleDisplay a rate as a percentage
  8. 8
    ChallengeCombine grouping and decimals
  9. 9
    ConnectionPad date and time parts
  10. 10
    ExplanationReserve the receipt fields
  11. 11
    ExampleCount the spaces in one row
  12. 12
    TipWidth does not shorten a long item
  13. 13
    ChallengeRead a filled and centered field
  14. 14
    ChallengeBuild a second receipt row
  15. 15
    ConnectionMatch the font to the layout
  16. 16
    RecapKeep calculation and presentation separate

Python Strings practice questions

50 Practice Questions in 5 sets

Set 1: Read literals, indexes, and slices10 Practice Questions

Question 1 of 10

What is the value of len("x\ty!")?
  1. 5
  2. 4
  3. 6
  4. 3
Show answerHide answer
Answer: B
The tab escape is one character, so the value contains x, a tab, y, and !. The outer quotes and the two written symbols used for \t are not additional characters in the value. Counting the escape as a backslash plus a letter would give five instead.

Question 2 of 10

What text does "Tag: " + str(8 * 2) produce?
  1. "Tag: 82"
  2. "Tag: 8 * 2"
  3. "Tag: 16.0"
  4. "Tag: 16"
Show answerHide answer
Answer: D
The multiplication runs first, giving the integer 16, and str() converts it to "16". Concatenation then adds it after "Tag: ". Joining the written digits as "82" would require string operands; the expression here multiplies two integers before conversion.

Question 3 of 10

What does r"D:\temp" store after the colon?
  1. A backslash followed by temp.
  2. A tab followed by emp.
  3. Two backslashes followed by temp.
  4. A newline followed by temp.
Show answerHide answer
Answer: A
The raw prefix keeps the backslash as a literal character, so it remains before the letters temp. In an ordinary literal, the initial \t would become a tab. Raw syntax does not add a second backslash to the stored string; the one written backslash stays one character.

Question 4 of 10

With code = "R7K2", what is code[-2]?
  1. "7"
  2. "2"
  3. "K"
  4. "R"
Show answerHide answer
Answer: C
Negative indexes count from the end: -1 selects "2" and -2 selects "K". The value is a one-character string. Counting two characters from the left would select "7", but the negative sign makes the end of the string the starting reference point.

Question 5 of 10

With word = "orbit", what does word[len(word) // 2] return?
  1. "r"
  2. "i"
  3. It raises TypeError.
  4. "b"
Show answerHide answer
Answer: D
The length is five, so floor division by two gives the integer index 2. Indexes 0, 1, and 2 select o, r, and b, making "b" the middle character. TypeError would occur with a float index, but // produces an integer here.

Question 6 of 10

What happens when this code runs with line = ""?

if len(line) > 0 and line[0] == ";":
    print("Skip")
  1. It raises IndexError before testing length.
  2. It prints nothing and raises no error.
  3. It prints "Skip" once and stops.
  4. It raises TypeError at the condition.
Show answerHide answer
Answer: B
The length test is false, so and skips the character read and the body does not run. The empty string would cause IndexError if line[0] were evaluated. Here the order of the tests keeps that index from being used on empty input.

Question 7 of 10

What is "notebook"[2:5]?
  1. "teb"
  2. "tebo"
  3. "ote"
  4. "te"
Show answerHide answer
Answer: A
The slice selects indexes 2, 3, and 4: t, e, and b. Stop index 5 is excluded, so its o does not appear. Including that character would give "tebo", which comes from treating the stop as inclusive instead of as the first position left out.

Question 8 of 10

What is the result of "map"[1:50]?
  1. "a"
  2. ""
  3. "ap"
  4. It raises IndexError.
Show answerHide answer
Answer: C
The slice starts at index 1 and continues to the end because the oversized stop is clipped. That keeps a and p, giving "ap". A single-character read such as "map"[50] would raise IndexError, but slice boundaries can extend beyond the available characters.

Question 9 of 10

What does "0123456789"[1:8:3] return?
  1. "148"
  2. "147"
  3. "1357"
  4. "1478"
Show answerHide answer
Answer: B
Start at index 1 and advance three positions at a time: 1, 4, and 7. The next position would be 10, beyond the excluded stop 8. "1357" uses a step of two; the third slice argument is the distance between selected positions, not the number of characters wanted.

Question 10 of 10

With s = "red-blue", what is s[-4:][::-1] + s[:3]?
  1. "derblue"
  2. "eulb-red"
  3. "eulbred"
  4. "blueeulb"
Show answerHide answer
Answer: C
The final four characters are "blue"; reversing that slice gives "eulb". The prefix s[:3] is "red", so concatenation gives "eulbred". The hyphen at index 3 belongs to neither selected slice and is not inserted automatically when the strings are joined.
Set 2: Trace loops and new string values10 Practice Questions

Save this lesson to see every answer and practice every set.

Question 1 of 10

How many times does the body of for ch in "a b!": run?
  1. 2
  2. 3
  3. 4
  4. 5
Show answerHide answer

Save this lesson to see this answer.

Question 2 of 10

What is printed?

total = 0
for ch in "Route 68":
    if ch.isdecimal():
        total += int(ch)
print(total)
  1. 14
  2. 2
  3. 68
  4. 8
Show answerHide answer

Save this lesson to see this answer.

Question 3 of 10

What is printed?

for ch in "Cab 53A":
    if ch.isdigit():
        print(ch)
        break
  1. 3
  2. 53
  3. 5 and then 3 on separate lines
  4. 5
Show answerHide answer

Save this lesson to see this answer.

Question 4 of 10

What is printed?

for i, ch in enumerate("lamp"):
    if i % 2 == 1:
        print(ch, end="")
  1. lm
  2. ap
  3. am
  4. lp
Show answerHide answer

Save this lesson to see this answer.

Question 5 of 10

What value is printed?

s = "aaabb"
pairs = 0
for i in range(len(s) - 1):
    if s[i] == s[i + 1]:
        pairs += 1
print(pairs)
  1. 2
  2. 3
  3. 4
  4. 1
Show answerHide answer

Save this lesson to see this answer.

Question 6 of 10

What text is printed?

s = "north"
i = len(s) - 1
result = ""
while i >= 0:
    result += s[i]
    i -= 2
print(result)
  1. hrn
  2. htr
  3. nrt
  4. hon
Show answerHide answer

Save this lesson to see this answer.

Question 7 of 10

What does b contain after this code?

a = "pine"
b = a
a = a.upper()
  1. "PINE" (all uppercase)
  2. "Pine" (only the initial uppercase)
  3. "" (empty text)
  4. "pine" (the original text)
Show answerHide answer

Save this lesson to see this answer.

Question 8 of 10

With s = "stone", what does s[:2] + "X" + s[3:] produce?
  1. "stXone"
  2. "sXone"
  3. "stXne"
  4. "stXo"
Show answerHide answer

Save this lesson to see this answer.

Question 9 of 10

What pair of values is printed?

word = "muse"
result = ""
for ch in word:
    if ch in "aeiou":
        result = ch.upper() + result
    else:
        result = ch + result
print(word, result)
  1. muse mUsE (unchanged word, forward masked result)
  2. mUsE EsUm (masked word, reversed masked result)
  3. muse Esum (unchanged word, one capital in result)
  4. muse EsUm (unchanged word, reversed masked result)
Show answerHide answer

Save this lesson to see this answer.

Question 10 of 10

What does this code print?

s = "  west  "
s.strip()
s = s + "!"
print(len(s))
  1. 5
  2. 6
  3. 9
  4. 8
Show answerHide answer

Save this lesson to see this answer.

Set 3: Clean, search, and validate text10 Practice Questions

Save this lesson to see every answer and practice every set.

Question 1 of 10

What does " Go Home ".strip().lower() return?
  1. "gohome" (no spaces)
  2. " go home " (outer spaces kept)
  3. "Go Home" (original case)
  4. "go home" (one internal space)
Show answerHide answer

Save this lesson to see this answer.

Question 2 of 10

What does "test.txt".rstrip(".txt") return?
  1. "test"
  2. "test."
  3. "tes"
  4. "test.tx"
Show answerHide answer

Save this lesson to see this answer.

Question 3 of 10

What is "A-a-a".replace("a", "x", 1).lower()?
  1. "a-x-a" (first lowercase match changed)
  2. "a-x-x" (both lowercase matches changed)
  3. "x-a-a" (initial letter changed)
  4. "A-x-a" (initial case kept)
Show answerHide answer

Save this lesson to see this answer.

Question 4 of 10

What is "cocoa".rfind("co")?
  1. 0
  2. 2
  3. 3
  4. 4
Show answerHide answer

Save this lesson to see this answer.

Question 5 of 10

What is printed?

s = "label"
p = s.find(":")
print(s[p:])
  1. l
  2. label
  3. An empty line
  4. It raises ValueError.
Show answerHide answer

Save this lesson to see this answer.

Question 6 of 10

What text is extracted?

s = "Item [K9] ready [Q2]"
a = s.find("[")
b = s.find("]", a)
result = s[a + 1:b]
  1. "[K9"
  2. "Q2"
  3. "K9"
  4. "K9] ready [Q2"
Show answerHide answer

Save this lesson to see this answer.

Question 7 of 10

What is "abababa".count("aba")?
  1. 3
  2. 1
  3. 0
  4. 2
Show answerHide answer

Save this lesson to see this answer.

Question 8 of 10

A form uses s = raw.strip() and then s.isdecimal() and int(s) > 0. Does raw input " 08 " pass, and what integer does it represent?
  1. It fails because of outer spaces.
  2. It passes and represents 8.
  3. It passes and keeps the text "08".
  4. It fails because of the leading zero.
Show answerHide answer

Save this lesson to see this answer.

Question 9 of 10

For a = " Cedar " and b = "cedar", what pair results from a == b and a.strip().casefold() == b.strip().casefold()?
  1. True, True
  2. False, False
  3. False, True
  4. True, False
Show answerHide answer

Save this lesson to see this answer.

Question 10 of 10

What pair results from "24" < "7" and int("24") < int("7")?
  1. False, False
  2. True, False
  3. False, True
  4. True, True
Show answerHide answer

Save this lesson to see this answer.

Set 4: Split records and rebuild text10 Practice Questions

Save this lesson to see every answer and practice every set.

Question 1 of 10

What is printed?

parts = "Mina;4;6".split(";")
total = int(parts[1]) + int(parts[2])
print(f"{parts[0]}:{total}")
  1. Mina:46
  2. Mina:4
  3. Mina:6
  4. Mina:10
Show answerHide answer

Save this lesson to see this answer.

Question 2 of 10

What is "mode=fast=quiet".split("=", 1)[1]?
  1. "fast"
  2. "quiet"
  3. "fast=quiet"
  4. "mode=fast"
Show answerHide answer

Save this lesson to see this answer.

Question 3 of 10

What does "status".partition(":") return?
  1. ("", ":", "status")
  2. ("status", ":", "")
  3. ("status", "", "")
  4. ("", "", "status")
Show answerHide answer

Save this lesson to see this answer.

Question 4 of 10

What does " / ".join("ab") produce?
  1. "a / b"
  2. "ab"
  3. "a / b / "
  4. " / a / b"
Show answerHide answer

Save this lesson to see this answer.

Question 5 of 10

What is "-".join("x::z:".split(":"))?
  1. "x-z"
  2. "x--z-"
  3. "x-z-"
  4. "x--z"
Show answerHide answer

Save this lesson to see this answer.

Question 6 of 10

What text is stored in result = " ".join(" bright\n blue sky ".split())?
  1. " bright blue sky "
  2. "brightblue sky"
  3. "bright blue sky"
  4. "bright blue sky"
Show answerHide answer

Save this lesson to see this answer.

Question 7 of 10

What does ": ".join(map(str, [6, 11])) produce?
  1. "6: 11"
  2. "6:11"
  3. "6: 11: "
  4. It raises TypeError.
Show answerHide answer

Save this lesson to see this answer.

Question 8 of 10

What is len(" one\ttwo three ".split())?
  1. 4
  2. 3
  3. 5
  4. 6
Show answerHide answer

Save this lesson to see this answer.

Question 9 of 10

What does "A||C|".split("|") return?
  1. ["A", "", "C", ""]
  2. ["A", "C"]
  3. ["A", "", "C"]
  4. ["A", "|C|"]
Show answerHide answer

Save this lesson to see this answer.

Question 10 of 10

What is "red;blue".split("; ")?
  1. ["red", "blue"]
  2. ["red", " blue"]
  3. ["red;blue"]
  4. ["red;", "blue"]
Show answerHide answer

Save this lesson to see this answer.

Set 5: Build readable values and columns10 Practice Questions

Save this lesson to see every answer and practice every set.

Question 1 of 10

With name = "Luca", what does f"Hi, {name.upper()}!" produce?
  1. "Hi, Luca!" (original name case)
  2. "Hi, {name.upper()}!" (unevaluated field)
  3. "Hi, LUCA!" (name uppercased)
  4. "HI, LUCA!" (whole message uppercased)
Show answerHide answer

Save this lesson to see this answer.

Question 2 of 10

What text is printed?

n = 4
label = f"{{n}}={n + 2}"
n = 9
print(label)
  1. {n}=11
  2. {n}=6
  3. 4=6
  4. 9=11
Show answerHide answer

Save this lesson to see this answer.

Question 3 of 10

What is f"{4826.5:,.2f}"?
  1. "4826.50"
  2. "4.826,50"
  3. "4,826.5"
  4. "4,826.50"
Show answerHide answer

Save this lesson to see this answer.

Question 4 of 10

What is f"{0.0375:.1%}"?
  1. "0.0%"
  2. "3.8%"
  3. "3.7%"
  4. "37.5%"
Show answerHide answer

Save this lesson to see this answer.

Question 5 of 10

With n = 0.125, what pair results from f"{n:.2f}" and n == 0.125?
  1. "0.12", True
  2. "0.13", True
  3. "0.12", False
  4. "0.13", False
Show answerHide answer

Save this lesson to see this answer.

Question 6 of 10

With month = 11, day = 6, year = 2028, hour = 7, and minute = 3, what does f"{month:02d}/{day:02d}/{year} {hour}:{minute:02d}" produce?
  1. "11/06/2028 7:03"
  2. "06/11/2028 7:03"
  3. "11/6/2028 7:3"
  4. "11/06/2028 07:03"
Show answerHide answer

Save this lesson to see this answer.

Question 7 of 10

What does f"|{'owl':>5}|" produce?
  1. "|owl |"
  2. "| owl |"
  3. "| owl|"
  4. "| owl|"
Show answerHide answer

Save this lesson to see this answer.

Question 8 of 10

With name = "seahorse", what are the contents and length of f"{name:6.4}"?
  1. "seahorse", length 8
  2. "seah", length 4
  3. "seah ", length 6
  4. " seah", length 6
Show answerHide answer

Save this lesson to see this answer.

Question 9 of 10

For item = "Tea", qty = 2, and price = 3.75, what is f"{item:<5}{qty:>2}{qty * price:>7.2f}"?
  1. "Tea 2 3.75"
  2. "Tea 2 7.50"
  3. "Tea 2 7.50"
  4. "Tea 2 7.500"
Show answerHide answer

Save this lesson to see this answer.

Question 10 of 10

What does f"{'otter':3}" produce?
  1. "ott"
  2. "ter"
  3. "otter"
  4. It raises ValueError.
Show answerHide answer

Save this lesson to see this answer.

Stuck on your own question? Homework Help

Key Terms

69 Key Terms, each with its definition

A

Accumulator
An accumulator is a variable that builds a running result across loop passes, such as a total number or a newly constructed string.
A string accumulator starting at "" can collect only nonspace characters to build "abc" from "a b c".
Alignment
Alignment decides where a value sits inside a padded field: < puts it left, > puts it right, and ^ centers it.
Right alignment in f"{'hi':>5}" puts three spaces before the word; left alignment puts them afterward.

B

Binary approximation
A binary approximation is a stored floating-point value close to a decimal quantity, which can affect rounding at a display boundary.
The binary approximation of float 2.675 is slightly low, so formatting at two decimal places gives "2.67".
break
The break statement exits the current loop immediately, allowing a character search to stop after processing its first matching character.
A first-digit search in "Zone 81" can print 8 and execute break, leaving the later 1 unprocessed.

C

Case folding
Case folding removes case distinctions for comparison, including some language-specific changes that ordinary lowercasing does not make.
Case folding turns both "Straße" and "STRASSE" into "strasse", letting the spellings compare equally.
Case-sensitive comparison
A case-sensitive comparison treats uppercase and lowercase characters as different, so matching words can still fail equality.
A case-sensitive comparison makes "Ready" == "ready" false until both values have consistent letter case.
Character test
A character test checks whether a string’s characters meet a rule, returning a Boolean; tests such as isalpha() also reject empty strings.
The character test "lake9".isalnum() is true, while the space in "lake 9" makes that version fail.
Code point conversion
Code point conversion uses ord() to obtain a character’s Unicode number and chr() to obtain the character for such a number.
Code point conversion with ord("A") gives 65, and the reverse conversion with chr(65) gives "A".
Concatenation
Concatenation combines strings end to end into one string, keeping all their characters without inserting a separator automatically.
Concatenation with "rain" + "coat" gives "raincoat"; adding a space requires a piece containing one.
Counter
A counter is a variable that records how many times a condition is met, usually starting at zero and increasing by one per match.
A digit counter for "Bay 27" increases on 2 and 7, finishing with two matches after the loop.

D

Decimal digit test
A decimal digit test, isdecimal(), accepts nonempty strings of decimal digit characters and rejects signs, decimal points, and spaces.
After outer spaces are stripped, the decimal digit test accepts "007", which converts to integer seven.

E

Empty field
An empty field is a zero-character item retained when explicit separators are adjacent or occur at a string’s beginning or end.
Splitting "a;;c" on ";" keeps an empty field in the second position, preserving a missing record value.
Empty separator
An empty separator is the zero-character string used with join() to put pieces together with no extra characters between them.
Using an empty separator in "".join(["a", "b", "c"]) gives "abc" while preserving the piece order.
enumerate()
The enumerate() function supplies each item of a sequence together with its index, allowing a loop to use both without a separate lookup.
A loop over enumerate("sun") receives index-character pairs beginning with 0, "s" and ending with 2, "n".
Escape sequence
An escape sequence uses a backslash and following characters in a literal to represent a character such as a newline, tab, or quote.
In "up\ndown", the escape sequence \n stores one newline, so printing puts the words on two lines.
Expression field
An expression field is a brace-enclosed part of an f-string whose expression is evaluated when the string is built.
The expression field in f"Total: {3 * 4}" computes twelve before inserting the result after the label.

F

F-string
An f-string is a string literal marked with f that evaluates expressions inside brace fields and inserts their values into the resulting text.
With count = 7, the f-string f"Found {count}" builds "Found 7" without an explicit numerical-to-text conversion.
Field conversion
Field conversion changes a text part into the type needed for further work, such as converting a split quantity with int() before addition.
Field conversion turns the split text "12" into an integer before it can be added numerically to five.
Field width
A field width sets a minimum number of character positions for a formatted value, adding padding while allowing longer values to remain whole.
A field width of five gives "cat" two trailing spaces, but width two still preserves the entire word.
Fill character
A fill character replaces ordinary space padding when placed directly before an alignment symbol in a format specifier.
An asterisk fill character in f"{'ok':*^6}" gives "**ok**", padding unused positions around the text.
find()
The find() method returns the starting index of the first matching substring, or -1 if the requested text does not occur.
The search "lemon".find("mo") returns two, while "lemon".find("xy") returns negative one for no match.
Fixed-point format
Fixed-point format uses the f type to display a number with a chosen number of decimal places, rounding and adding trailing zeros as needed.
Fixed-point format .3f shows the integer five as "5.000", with exactly three decimal places.
Format specifier
A format specifier is a set of display instructions after the colon in a field, controlling details such as precision, grouping, or width.
In f"{8.5:.2f}", format specifier .2f selects two decimal places, producing "8.50" for display.

I

Immutability
Immutability means a value cannot be changed in place; a string operation must produce another value to give a variable different text.
String immutability makes name[0] = "B" fail, while name = "B" + name[1:] builds new text successfully.
Index
An index is an integer position used to select one character of a string, with the first character at position zero.
For label = "desk", index 2 selects "s", since the positions begin with d at zero.
IndexError
An IndexError reports that an attempted sequence index has no item, such as selecting a position beyond the end of a string.
The expression "cup"[3] raises IndexError, since its three characters occupy positions zero through two.
Item assignment
Item assignment tries to replace a sequence item at an index; strings reject it because their characters cannot be edited in place.
Item assignment in word[1] = "x" raises TypeError for a string even when index one is a valid position.

J

Joining
Joining builds one string from string pieces, placing a chosen separator between consecutive pieces without adding it at either outer end.
Joining ["home", "nora"] with the separator "/" produces "home/nora", with one slash between the pieces.

L

Lexicographic order
Lexicographic order compares sequences from left to right, using the first differing character’s code point or placing a shorter prefix first.
Lexicographic order puts "19" before "3", because their first differing characters decide the comparison.
List
A list is an ordered collection of items written in square brackets; a string split returns a list whose items are strings.
After splitting "oak,elm" on a comma, the list contains two items and index one selects the string "elm".
Literal brace
A literal brace is a brace character displayed as text in an f-string by doubling it, keeping it separate from expression field syntax.
A literal brace in f"{{open}}" displays { around open without asking Python to evaluate that name.

M

map() conversion
A map() conversion applies a function to each input item, allowing str to supply the string pieces required by join().
A map() conversion in ", ".join(map(str, [3, 8])) supplies strings before joining them as "3, 8".
Maximum splits
The maximum splits argument limits how many cuts split() or rsplit() makes, leaving the rest together in an unsplit part.
Setting maximum splits to one cuts "a=b=c" into "a" and "b=c" from the left, keeping later equals signs.
Membership test
A membership test uses in or not in to check whether a substring occurs, returning a Boolean without giving its position.
The membership test "ice" in "spice" is true, while uppercase "Ice" does not match the same text.
Method chaining
Method chaining calls a method on the result of an earlier call, so each operation receives the value returned immediately before it.
Method chaining in " OK ".strip().lower() first returns "OK", then converts that result to "ok".
Monospaced font
A monospaced font gives each character position equal visual width, allowing repeated fixed-width fields to line up as text columns.
A monospaced font in a terminal makes equal-width cost fields align because every character position takes equal space.

N

Negative index
A negative index selects a character by counting from the end, where -1 is the last and -len(text) is the first.
In "cloud", negative index -1 selects "d", while -2 selects the preceding character "u".
Nonoverlapping matches
Nonoverlapping matches are occurrences that do not reuse any character positions, which is the matching rule used by count().
The two nonoverlapping matches in "aaaa".count("aa") use different character positions, so the count is two.

O

Off-by-one error
An off-by-one error uses a boundary one position too early or late, often by confusing a sequence’s length with its final index.
An off-by-one error in text[len(text)] reads past the end; subtracting one gives the final character index.

P

Padding
Padding adds characters to reach a minimum field width, using spaces, zeros, or a chosen fill while preserving longer values.
Padding with "5".zfill(3) produces "005", while the already longer "1234" stays unchanged at width three.
Palindrome
A palindrome is text that reads the same forward and backward, so comparing a string with its reverse can test this property.
The palindrome "radar" passes word == word[::-1]; mixed case needs cleanup when case should be ignored.
Partition
A partition separates text once into a three-part tuple containing the text before a separator, the separator, and the text after it.
The partition of "color=blue" at "=" is ("color", "=", "blue"), retaining the separator in the middle.
Percentage format
Percentage format uses % to multiply a fraction by 100 for display and append a percent sign, with optional decimal precision.
Percentage format .0% shows 0.18 as "18%"; supplying eighteen would scale the value a second time.

R

Raw string literal
A raw string literal has an r prefix that keeps backslashes as literal characters instead of processing ordinary escape sequences.
The raw string literal r"C:\new" keeps the backslash before new, preventing that pair from becoming a newline.
Reassignment
Reassignment makes a variable refer to a different value, without changing the value it previously referred to or other names for that value.
When a holds "red", reassignment with a += "!" makes a refer to "red!" while another variable can still hold "red".
removeprefix()
The removeprefix() method removes one exact matching beginning from a string, returning the original text when that beginning is absent.
The call "pretest".removeprefix("pre") gives "test", while a missing prefix leaves the text unchanged.
removesuffix()
The removesuffix() method removes one exact matching ending from a string, preserving other characters that stripping might remove.
The call "report.txt".removesuffix(".txt") keeps "report", including the final t in the base name.
Return value
A return value is the result a function or method gives back to its caller, which can be saved, tested, or passed to another operation.
The return value of text.upper() is uppercase text; assigning it to text keeps it for later use.
rfind()
The rfind() method returns the starting index of the last matching substring, using the whole string’s positions even though it searches from the right.
The search "a-b-c".rfind("-") returns three, locating the final hyphen with a position counted from the left.
Rounding to even
Rounding to even chooses the even retained digit when a stored value lies exactly halfway between two possible rounded results.
Rounding to even makes exact ties 0.125 and 0.375 display as "0.12" and "0.38" at two places.

S

Search start position
A search start position sets the earliest position considered by a search while keeping returned indexes relative to the whole string.
A search start position of one in "cocoa".find("co", 1) skips the match at zero and finds the one at two.
Separator
A separator is the exact string that marks a split boundary or is placed between pieces by a join, and it may contain several characters.
The separator ", " matches a comma followed by a space, so it does not split the string "oak,elm".
Short-circuit evaluation
Short-circuit evaluation skips a Boolean operand when the earlier result already decides the condition, allowing a first test to protect a later operation.
Short-circuit evaluation in s.isdecimal() and int(s) > 0 skips conversion when the character test fails.
Slice
A slice selects characters using a start, an excluded stop, and an optional step, returning the selected text as a string.
The slice "window"[1:4] returns "ind", selecting positions one through three and excluding position four.
Slice boundary
A slice boundary marks where selection begins or ends; a forward slice includes its start position and excludes its stop position.
In "garden"[:3], slice boundary three is the excluded stop, so d is left out and the result is "gar".
Slice step
A slice step is the nonzero integer distance between selected positions, with a negative value making selection move backward.
A slice step of two in "abcdef"[::2] selects indexes zero, two, and four, producing "ace".
str.format()
The str.format() method fills brace fields in a string using its arguments, with fields selected by order or an explicit argument index.
The call "{1}, {0}".format("Ada", "Lovelace") uses str.format() to put the second argument before the first.
String
A string is an ordered sequence of Unicode characters with type str, used to store text such as names, messages, and codes.
The string "Hello, Nora" stores the greeting, its comma, and its space as part of one ordered text value.
String literal
A string literal is text written directly in Python code between matching quotes, which mark its boundaries without entering the value.
The string literals "open" and 'open' use different outer quotes but store the same four characters.
String method
A string method is a function attached to string values, called with a dot and parentheses to perform a text operation and return its result.
The string method call "hello".upper() returns "HELLO"; leaving off the parentheses does not call it.
String precision
String precision limits how many characters of text a field displays, letting a maximum text length combine with a minimum width.
String precision in f"{'sunshine':6.3}" displays "sun" and three spaces without changing the original word.
String traversal
String traversal visits characters in a chosen order, commonly with a direct for loop or a while loop using an index.
String traversal over "go!" visits g, then o, then !, allowing a separate decision for each character.
Stripping
Stripping removes unwanted characters from a string’s ends, using whitespace by default or a specified set of removable characters.
Stripping "..hello!!" with the character set ".!" keeps "hello", leaving internal text untouched.
Substring
A substring is a consecutive sequence of characters within another string, which can be selected by slicing or found by searching.
The text "light" is a substring of "daylight", but "dyl" is not because those letters are not consecutive.

T

Thousands grouping
Thousands grouping separates large numbers into readable groups using a comma or underscore in a format specifier.
Thousands grouping in f"{7654321:,}" displays "7,654,321", separating each group of three digits.

U

Unicode code point
A Unicode code point is a number assigned to a character; Python strings store code points, and len() counts them.
The emoji "👍🏽" contains two Unicode code points, so its Python string length is two despite its appearance.

W

Whitespace
Whitespace consists of spacing characters such as spaces, tabs, and line breaks, which text methods can trim or use as boundaries.
The string " \t" contains only whitespace, and stripping it removes both characters to leave empty text.
Whitespace cleanup
Whitespace cleanup with " ".join(text.split()) trims the ends and replaces internal whitespace runs with a single ordinary space.
Whitespace cleanup with " ".join(text.split()) turns " blue\n sky " into the consistently spaced "blue sky".

Z

Zero padding
Zero padding adds leading zeros to reach a minimum numeric width, making short integers suitable for codes and date or time parts.
Zero padding in f"{4:02d}" displays "04", allowing a one-digit minute to fill a two-digit field.

About this lesson

By StudeliReport a mistake

Make your own Study Materials

Turn your notes, slides and documents into Study Guides, Practice Questions, Flashcards and 6 more tools.

Get Started