Learn · Run · Break · Fix
A learning series from A Wandering Mind
Eighteen interlinked lessons on strings, lists, files, exceptions, and dictionaries—with original explanations, runnable examples, real output, and supporting CPSC 1301K lectures.
>>> guide = { ... "lessons": 18, ... "modules": 5, ... "python": "3.10+" ... } >>> guide["goal"] = "understand it"
Splitting and Joining Strings in Python
Real programs rarely receive text in exactly the shape they need. Python’s split() method breaks one string into useful pieces, while join() combines string pieces into a new string. By the end of this lesson, you will be able to choose separators, limit a split, rebuild text cleanly, and diagnose several errors that appear when the pieces do not match your assumptions.
split() produces a list of string pieces.Two operations that move text in opposite directions
Imagine receiving the text "Ada|Lovelace|1815|London". A person can see four fields separated by vertical bars, but Python initially sees one string. If the program needs to work with the first name, last name, year, and city independently, it needs a way to break that single string apart. That is what split() does.
join() travels in the other direction. If the program already has several string values and needs one finished line, filename, path, label, or slug, join() inserts a chosen separator between those values. Together, the two methods form a useful pattern: parse text into pieces, work with the pieces, then assemble text for display or storage.
split()text.split(separator)Starts with one string and returns pieces. With no separator argument, runs of whitespace are treated as separators.
join()separator.join(strings)Starts with multiple string values and returns one new string with the separator placed between them.
Using split() with ordinary whitespace
Calling split() with no argument is more useful than it may first appear. Python treats spaces, tabs, and line breaks as whitespace and collapses repeated whitespace while making the split. That makes the no-argument form useful when the exact number of spaces does not matter.
text = "Python strings\tare useful"
parts = text.split()
print(parts)
print(f"Words: {len(parts)}")
['Python', 'strings', 'are', 'useful']
Words: 4
Notice that the three spaces between Python and strings do not create empty pieces, and the tab between strings and are works like another separator. The result is displayed with square brackets because split() returns a list. You do not need to master lists yet; for now, treat the result as an ordered collection of the pieces Python found. The next lesson, Creating Lists, will make that structure explicit.
Using an exact separator
When the text follows a known format, pass that separator to split(). A pipe, comma, colon, slash, or another substring can mark the boundary between fields. Unlike the no-argument form, an explicit separator is literal: Python looks for exactly the characters you supplied.
record = "Ada|Lovelace|1815|London"
first, last, year, city = record.split("|")
print(first)
print(last)
print(f"{city}, {year}")
Ada
Lovelace
London, 1815
Here Python finds three vertical bars and therefore produces four pieces. The assignment on the second line expects exactly four values, so each piece is placed into a matching variable. This is convenient when the input format is predictable, but it also creates an important responsibility: if the number of pieces changes, the assignment can fail. We will see that failure in the Common mistakes section.
A separator is removed by the split. In the example above, none of the resulting values contains |. If that punctuation matters later, you must deliberately add it back when producing new output.
Joining pieces into one new string
The syntax for join() often surprises beginners because the separator comes first. You write "-".join(words), not words.join("-"). A useful way to read it aloud is: “Use this hyphen to join these strings.” The method belongs to the separator string because that string decides what will be inserted between every pair of values.
words = ["learn", "python", "one", "step", "at", "a", "time"]
slug = "-".join(words)
print(slug)
learn-python-one-step-at-a-time
join() inserts the hyphen only between items. It does not add one at the beginning or end. The same method can create comma-separated output, breadcrumb-like labels, file paths, or readable sentences when you already have the pieces as strings. That is often cleaner than repeatedly using +, especially when the number of pieces can grow.
Limiting the number of splits
split() accepts an optional second argument called maxsplit. It tells Python the maximum number of times to split the original string. This matters when the separator may also appear inside the final field and you want to preserve the remainder.
path = "resources/computer-science/python/strings"
pieces = path.split("/", 2)
print(pieces)
print(" → ".join(pieces))
['resources', 'computer-science', 'python/strings']
resources → computer-science → python/strings
Although the original path contains three slashes, maxsplit=2 allows only two splits. The unsplit remainder becomes the final piece: python/strings. The last line then uses join() to turn the three pieces into a readable trail. This example shows why the two methods are useful together without implying that they undo one another automatically; the new separator is completely your choice.
split() and join() do not modify the original string
Python strings are immutable. Calling either method creates a new result rather than changing the original string in place. If you need the result later, assign it to a variable. This same “produce a new value” idea explains why a chain such as text.split() can be passed into another operation without rewriting text itself.
It also helps to separate parsing from presentation. Use split() when your program needs to understand the structure of incoming text. Use join() when your program needs to present several strings as one finished value. That distinction becomes especially important later when reading lines from files, because each line often needs to be parsed into fields before the program can use it.
Common mistakes and what Python is telling you
These examples are deliberately wrong. The tracebacks below were generated by running the code as shown. Read the final line first; it names the exception and usually gives the clearest clue about what assumption failed.
record = "name:score:grade"
name, score = record.split(":")
Traceback (most recent call last):
File "/tmp/lesson2_unpack.py", line 2, in <module>
name, score = record.split(":")
^^^^^^^^^^^
ValueError: too many values to unpack (expected 2)
The string contains two colons, so the split produces three pieces. The assignment has only two variable names. Either provide three destinations, change the input format, or deliberately limit the split if only the first boundary matters.
numbers = [1, 2, 3]
print(",".join(numbers))
Traceback (most recent call last):
File "/tmp/lesson2_join_type.py", line 2, in <module>
print(",".join(numbers))
~~~~~~~~^^^^^^^^^
TypeError: sequence item 0: expected str instance, int found
join() combines strings. It does not automatically convert every object the way an f-string often does for display. The message identifies the first offending item as an integer. Convert or format numeric values into strings before joining them.
text = "abc"
print(text.split(""))
Traceback (most recent call last):
File "/tmp/lesson2_separator.py", line 2, in <module>
print(text.split(""))
~~~~~~~~~~^^^^
ValueError: empty separator
An empty string does not define a boundary, so split("") is invalid. If the real goal is to work with individual characters, that is a different operation from splitting on a separator.
words = ["python", "strings"]
print(words.join("-"))
Traceback (most recent call last):
File "/tmp/lesson2_join_owner.py", line 2, in <module>
print(words.join("-"))
^^^^^^^^^^
AttributeError: 'list' object has no attribute 'join'
The wording tells you that Python looked for a method named join on a list and could not find one. Reverse the relationship: "-".join(words). The separator string owns the method; the collection of strings is passed to it.
Supporting classroom explanations
This written lesson is designed to stand on its own. The two assigned CPSC 1301K lectures below provide shorter classroom-style explanations of the same core operations. They are supporting references, not the source of the examples or wording on this page.
What it adds: a focused lecture pass on how Python divides strings into pieces, reinforcing the separator behavior after you have practiced it here.
What it adds: a compact visual explanation of the separator-first join() syntax, which is often the part beginners need to see twice.
Try it yourself
Predict the result before running each exercise. When you open an answer, compare not just the final output but also which object calls the method and what separator Python is using.
Exercise 1 · Normalize spaced words
Start with text = "red green\tblue". Split the text on whitespace, then join the pieces with " | " so the output is red | green | blue.
Show one answer
text = "red green\tblue"
parts = text.split()
print(" | ".join(parts))
red | green | blue
Exercise 2 · Read three fields
Start with location = "Savannah|Georgia|USA". Split it into three variables and use an f-string to print Savannah, Georgia, USA.
Show one answer
location = "Savannah|Georgia|USA"
city, state, country = location.split("|")
print(f"{city}, {state}, {country}")
Savannah, Georgia, USA
Exercise 3 · Build an underscore-separated label
Given words = ["python", "string", "practice"], use join() to print python_string_practice.
Show one answer
words = ["python", "string", "practice"]
print("_".join(words))
python_string_practice
Where this goes next
You have now seen two string operations that naturally lead into collections. split() gives you several pieces at once, and join() can consume several string pieces to produce one final value. The next module slows down and examines that collection directly: how to create a list, how an empty list works, and why lists become one of Python’s most useful general-purpose structures.
