Course outline · 0% complete

0/32 lessons0%

Course overview →

Indexing and Slicing

lesson 2-1 · ~12 min · 4/32

Recall from lesson 1-3 that / and // behave differently. The type of 10 / 5 is float, because / always produces a float.

Even a division that comes out exactly even follows that rule, so 10 / 5 is 2.0 rather than 2. Getting a whole number requires 10 // 5, which gives the int 2. This distinction returns in unit 3, where values arriving from outside the program have to be converted before arithmetic works on them.

A string is a sequence of characters

Almost everything a program receives from the outside world arrives as a string: usernames, file names, dates, whole files. Pulling pieces out of them, the year from "2026-07-06", the extension from "report.pdf", is daily work for any engineer, and indexing and slicing are the tools that do it.

Every character in a string has a numbered position called an index. Counting starts at 0, not 1. You read one character with square brackets, and len() tells you how many characters there are.

word = "Python"
#       P  y  t  h  o  n
#       0  1  2  3  4  5

Negative indexes count from the end: word[-1] is the last character, word[-2] the one before it. That saves you from writing word[len(word) - 1].

Asking for an index that does not exist, like word[6] here, stops the program with an IndexError.

Python012345-6-5-4-3-2-1index
Indexes for "Python": 0 to 5 from the front, -1 to -6 from the back. The pointer steps through each position.

Reading single characters by index

Each line below picks one position out of the string, using the numbering from the diagram above.

word = "Python"
print(len(word))
print(word[0])
print(word[5])
print(word[-1])
print(word[-2])

Output

6
P
n
n
o

The len call reports 6 characters, and because counting starts at 0 the valid indexes run from 0 to 5. Notice that word[5] and word[-1] print the same n: they are two ways of naming the final position, one counting forward from the start and one counting backward from the end.

Slicing: grabbing a piece

A slice copies a range of characters: word[start:stop] takes from index start up to but not including stop.

word = "Python"
word[0:2]   # "Py"   indexes 0 and 1
word[2:6]   # "thon"

Leave a side empty and Python fills in the edge: word[:2] means from the start, word[2:] means to the end. A handy way to read s[:n] is "the first n characters".

Slices never fail with an error. word[2:100] just stops at the end and gives "thon".

A pair of slices can split a string into two parts without any letters being retyped. The first slice takes everything up to index 3, and the second takes everything from index 3 onward.

s = "keyboard"
print(s[:3])
print(s[3:])

Output

key
board

The first three characters occupy indexes 0, 1, and 2, so s[:3] covers them, stopping just before index 3 as slices always do. Because s[3:] starts exactly where the first slice stopped, the two pieces fit together with nothing missing and nothing duplicated.

Slicing fields out of a date

Real data often packs several fields into one string, and slicing is how they come apart. In a date written YYYY-MM-DD the dashes occupy indexes 4 and 7, so each field is a slice that steps over them.

date = "2026-07-06"
year = date[:4]
month = date[5:7]
day = date[8:]
print(year)
print(month)
print(day)

Output

2026
07
06

Each slice is positioned around the separators. The year is date[:4], covering indexes 0 through 3 and stopping before the first dash. The month starts at index 5 to skip that dash and runs to date[5:7], stopping before the second one. The day is date[8:], which takes everything after the second dash without needing to know the string's length.