Accessing One Element
Indexing selects one element by position from a string or list. For example, if letters = ["a", "b", "c"], then letters[1] returns "b".
Python starts its index numbers at . The first element has index , the second has index , and so on. Python also supports negative indices that count backward from the end.
Positive and Negative Indices
In strings or lists, each character or element has two types of indices. Positive indices start from at the beginning, while negative indices start from at the end.
The table places two indices on the same element. Both 1 and -4 select e. The code uses repr() so quotation marks and empty strings remain visible in the output.
| Character | H | e | l | l | o |
|---|---|---|---|---|---|
| Index from start | 0 | 1 | 2 | 3 | 4 |
| Index from end | -5 | -4 | -3 | -2 | -1 |
# Example of indexing on string
s = "Hello"
# Accessing characters with positive indices
print(repr(s[0])) # Output: 'H'
print(repr(s[4])) # Output: 'o'
# Accessing characters with negative indices
print(repr(s[-1])) # Output: 'o'
print(repr(s[-5])) # Output: 'H'
# Trying to access non-existent index
try:
print(repr(s[5]))
except IndexError:
print("IndexError: index out of range")An index outside the valid range raises IndexError. This bounds check prevents Python sequences from returning an unrelated value.
Selecting Several Elements
A slice selects several elements from a string or list. You set a start index, a stop index, and, when needed, the distance between selected elements.
Slices with Two Bounds
The syntax [i:j] uses i as the start index and j as the stop index. The result includes the element at i but excludes the element at j.
# Example of slicing on string
s = "Hello"
# Slicing from index 1 to 3 (not including 3)
print(repr(s[1:3])) # Output: 'el'
# Slicing from index 3 to end
print(repr(s[3:])) # Output: 'lo'
# Slicing from start to index 3
print(repr(s[:3])) # Output: 'Hel'
# Slicing with negative indices
print(repr(s[-4:-2])) # Output: 'el'
print(repr(s[-2:-4])) # Output: ''When the start index is greater than the stop index and the step is positive, the result is an empty string or list. A negative step selects items in the opposite direction.
Setting the Distance Between Items
The third parameter in [start:stop:step] sets the distance between selected elements. A step of 2, for example, selects one item and skips the next.
# Example of slicing with stride
s = "Hello World!"
# Taking every second character
print(repr(s[::2])) # Output: 'HloWrd'
# Taking every second character from index 1
print(repr(s[1::2])) # Output: 'el ol!'
# Reversing string with negative stride
print(repr(s[::-1])) # Output: '!dlroW olleH'
# Slicing with negative stride from specific index
print(repr(s[-1:4:-1])) # Output: '!dlroW 'A negative step reverses the selection direction. The form s[::-1] omits both bounds and selects every element from the end to the beginning. A step cannot be zero because it would never advance to another index.
Slice Rules
A slice is written as start:stop:step. The start index is included, the stop index is excluded, and a negative step walks the sequence from right to left.
Counting the Selected Elements
Let be the length of s. For the simple case with the default positive step, s[i:j] has length . General slices may contain omitted, negative, or out-of-range bounds and a different step. Python first normalizes them against the sequence length. The exact count is len(range(*slice(i, j, step).indices(len(s)))).
# Calculating slicing result length
s = "Hello"
# Slicing s[1:4]
result = s[1:4]
print(f"Result: '{result}', Length: {len(result)}") # Output: Result: 'ell', Length: 3
# Proving that s[:i] + s[i:] == s
i = 2
left_part = s[:i]
right_part = s[i:]
print(f"'{left_part}' + '{right_part}' = '{left_part + right_part}'")
# Slicing outside bounds doesn't cause error
print(repr(s[3:10])) # Output: 'lo'
print(repr(s[10:])) # Output: ''Python clips slice bounds to the valid range of the string or list. Therefore, s[3:10] remains valid even when the stop index is greater than the length of s.
Indices Selected by a Slice
The loop below rebuilds the slice with range(start, stop, step), one index at a time.
# Understanding slicing as loop
s = "Hello World!"
# s[1:8:2] equivalent to the following loop:
result_manual = ""
for index in range(1, 8, 2):
result_manual += s[index]
result_slicing = s[1:8:2]
print(f"Manual loop: '{result_manual}'") # Output: 'el o'
print(f"Slicing: '{result_slicing}'") # Output: 'el o'
print(f"Same? {result_manual == result_slicing}") # Output: True
# Example with negative stride
print("\nNegative stride:")
print(f"s[::-2] = '{s[::-2]}'") # Output: '!lo le'
# Equivalent manual loop for negative stride
result_negative = ""
for index in range(len(s)-1, -1, -2):
result_negative += s[index]
print(f"Manual: '{result_negative}'")Comparing the slice with its range() model shows how start, stop, and step work together, especially when the step is negative.
Slice Shorthand
Omitted bounds follow the step direction. A positive step starts at the beginning by default and stops after the final element. A negative step starts at the final element by default and stops beyond the first element.
From the Beginning or to the End
With the default positive step, s[:3] selects the beginning and s[3:] selects the end. In s[::-1], both omitted bounds follow the negative direction, reversing the sequence.
# Useful slicing variations
s = "Hello"
# Taking first 3 characters
print(repr(s[:3])) # Output: 'Hel'
# Taking characters from index 3 to end
print(repr(s[3:])) # Output: 'lo'
# Taking all characters
print(repr(s[:])) # Output: 'Hello'
# Practical example with list
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# Taking first 5 elements
first_five = numbers[:5]
print(f"First five: {first_five}")
# Taking last 5 elements
last_five = numbers[-5:]
print(f"Last five: {last_five}")
# Taking middle elements (skip first 2 and last 2)
middle = numbers[2:-2]
print(f"Middle part: {middle}")These forms select a specific region or regularly spaced items from a larger dataset without a separate loop.
Working with Parts of Strings and Lists
The examples below use indexing and slicing to reverse strings, format phone numbers, build initials, and check palindromes. The file extension example uses Path.suffix because extensions do not have a fixed length.
# Practical examples of indexing and slicing
# 1. Reversing name
first_name = "Ahmad"
last_name = "Wijaya"
reversed_name = (first_name + " " + last_name)[::-1]
print(f"Reversed name: {reversed_name}")
# 2. Getting a file extension safely
from pathlib import Path
filename = "important_document.pdf"
extension = Path(filename).suffix
print(f"Extension: {extension}")
# 3. Formatting phone number
number = "081234567890"
formatted = f"{number[:4]}-{number[4:8]}-{number[8:]}"
print(f"Formatted number: {formatted}")
# 4. Getting name initials
full_name = "Siti Nurhaliza Binti Ahmad"
words = full_name.split()
initials = ""
for word in words:
initials += word[0]
print(f"Initials: {initials}")
# 5. Palindrome checker
def is_palindrome(text):
cleaned = "".join(character for character in text.casefold() if character.isalnum())
return cleaned == cleaned[::-1]
print(f"'katak' palindrome? {is_palindrome('katak')}")
print(f"'kasur rusak' palindrome? {is_palindrome('kasur rusak')}")Use an index to select one item at a known position. Use a slice to select several adjacent or regularly spaced items. The form [::-1] reverses their order. For file extensions, avoid a fixed number of characters because extension lengths vary. Path.suffix reads the extension from the path structure.
Slice bounds are clipped to the sequence, so s[10:] on a shorter string returns "". Direct indexing such as s[10] still raises IndexError. Use a slice only when an empty result is acceptable.
Negative indices count from the end. Use s[-1] for the last element or s[-3:] for the last three elements. This form selects positions near the end during file processing, text parsing, or dataset work.