Indexing & Slicing

Beginner · 18 min read · ▶ live playground · ✦ checkpoint

A string looks like one solid piece of text until you ask for just one letter. Then Python shows its secret: every character has a numbered place, and you can point to one place or carve out a smaller piece.

Positions start at zero

An index is a numbered position inside a string. Think of a string as text laid on a ruler: Python starts the ruler at 0, so the first character is at index 0, not 1.

player = "Mina"
character_count = len(player)
last_index = character_count - 1
 
print(player[0])
print(player[1])
print(player[2])
print(player[3])
print(character_count)
print(last_index)
print(player[last_index])

M
i
n
a
4
3
a

The square brackets say "give me the character at this position." player[0] reads as "from player, get position zero."

This feels strange at first because humans usually count the first thing as one. Python counts how many steps you move from the left edge of the string. To reach M, you move zero steps. To reach i, you move one step.

The built-in function len() is reusable behavior Python already gives you; here, it counts the characters in a string. Functions get their full story in lesson 7.1.

For a four-character string, the last index is 3. That is the zero-start rule in action: the count is one higher than the last valid position.

This is the habit to build: use the count when you want to know how many characters exist, and use an index when you want to reach a character. Those are related numbers, but they are not the same number.

Negative positions count from the end

A negative index is a position counted backward from the end of a string. -1 means "last character," -2 means "second from last," and so on.

score_word = "score"
 
print(score_word[-1])
print(score_word[-2])
print(score_word[-3])
print(score_word[0])
print(score_word[-5])

e
r
o
s
s

Negative positions are not a different string. They are another way to point at the same ruler, starting from the right edge this time. score_word[0] and score_word[-5] both reach the same s.

Use positive indexes when you care about the start. Use negative indexes when you care about the end. The last letter is almost always clearer as word[-1] than as word[len(word) - 1].

You do not need to convert the negative number into a positive one in your head every time. Read word[-1] as "last," word[-2] as "one before last," and keep moving left from there. The code should help your eyes, not turn every string into arithmetic homework.

Slices take a piece

A slice is a smaller string made from part of another string, using the bracket pattern start:stop. The start index is included. The stop index is not included.

Picture slicing a ribbon between ruler marks: cut at the start mark, then cut just before the stop mark. The second mark is where the slice stops, not the last character you keep.

message = "Mina scored 42"
 
print(message[0:4])
print(message[5:11])
print(message[12:14])
print(message[:4])
print(message[12:])

Mina
scored
42
Mina
42

message[0:4] gives you positions 0, 1, 2, and 3. It stops before 4. That "stop before" rule is the one that prevents many off-by-one mistakes once it clicks.

For normal positive-step slices, leaving out the start means "start at the beginning," and leaving out the stop means "go to the end." A default is the value Python uses when you leave a part out.

A single index and a slice look similar, but they answer different questions. message[0] asks for one character. message[0:4] asks for a piece of the string. If a colon appears inside the brackets, you are slicing.

Try it - slice a game message

Change the numbers, then run again. Predict each result before you press Run.

python — playgroundlive
⌘/Ctrl + Enter to run

Step skips through the slice

A slice can have three parts: start:stop:step. The step is the size of each move Python makes while collecting characters.

The default step is 1, which means "take every character in order." A step of 2 means "take one, skip one, take one, skip one."

mood = "ready"
 
print(mood[0:5:1])
print(mood[0:5:2])
print(mood[1:5:2])
print(mood[::-1])

ready
ray
ed
ydaer

mood[0:5:2] starts at 0, stops before 5, and moves by twos. That collects r, then a, then y.

The slice mood[::-1] has no start and no stop, but it has a step of -1. With that backward step, the omitted start begins at the right end, and the omitted stop keeps going past the left edge. That creates a reversed copy of the string.

You won't need fancy steps every day. But reading start:stop:step now makes slices feel like one rule instead of a pile of special cases.

Strings do not change in place

Immutability means a value cannot be changed in place after Python creates it. Strings are immutable: you can read player[0], but you cannot assign a new character into player[0].

player = "mina"
player[0] = "M"

That failed line raises TypeError: 'str' object does not support item assignment. Python is saying: a string position is readable, not writable.

This does not break the name tag model from lesson 2.1. You can still build a new string and move the name to it. You just do not edit the old string object.

player = "mina"
fixed_player = "M" + player[1:]
 
print(player)
print(fixed_player)
 
player = fixed_player
print(player)

mina
Mina
Mina

player[1:] means "everything from index 1 to the end." Concatenation makes a new string, "Mina". The old "mina" string was not patched; the name player moved to the new object on the last assignment.

Checkpoint

Answer all three to mark this lesson complete

You can now reach into a string with positions and carve out exact pieces with slices. Next, you trade bracket math for Python's everyday string tools and cleaner formatting moves.

+50 XP on completion