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"
Slicing Lists and Testing Membership in Python
Indexing retrieves one position from a list. Slicing retrieves a range of positions, and membership tests ask whether a particular value appears anywhere in the collection. Together, slices and the in / not in operators let you select useful portions of a list and make decisions about the values they contain.
A slice selects a range instead of one position
Ordinary indexing uses one integer inside square brackets: items[2]. Slicing uses a colon to describe a range: items[start:stop]. Python begins at the start index and continues up to—but does not include—the stop index.
That exclusive stop boundary is one of the most important slicing rules. For a list with indexes 0 through 5, the slice items[1:4] contains positions 1, 2, and 3. Position 4 marks where the slice stops.
numbers = [10, 20, 30, 40, 50, 60]
print(numbers[1:4])
print(numbers[:3])
print(numbers[3:])
[20, 30, 40]
[10, 20, 30]
[40, 50, 60]
The first line supplies both boundaries. The second omits the start, so Python begins at the front of the list. The third omits the stop, so Python continues through the end. These shortened forms are useful because they express intent directly: items[:3] means “the first three items,” while items[3:] means “everything from index three onward.”
Remember: the start position is included; the stop position is excluded. This is why items[0:3] contains three elements rather than four.
Slices can include a step
A third value controls the distance between selected positions: items[start:stop:step]. A step of 2 takes every second item. If the start and stop are omitted, items[::2] walks across the entire list two positions at a time.
A negative step reverses direction. The compact slice items[::-1] is a common way to produce a reversed list sequence. It does not reverse the original list in place; it produces the elements in reverse order as a slice result.
letters = ["a", "b", "c", "d", "e", "f"]
print(letters[::2])
print(letters[::-1])
['a', 'c', 'e']
['f', 'e', 'd', 'c', 'b', 'a']
The first slice selects indexes 0, 2, and 4. The second uses a step of -1, so Python walks backward through the whole sequence. More complex negative-step slices are possible, but these two patterns are enough to establish what the third slice component means.
Slicing is more forgiving than single-item indexing
In Lesson 4, asking for a single index beyond the end of a list raised IndexError. A slice behaves differently. If the stop boundary extends beyond the available positions, Python generally takes as many items as exist and stops at the end.
For example, a three-item list can safely be sliced with items[:100]. The result contains the available three items rather than raising an exception. This makes slicing convenient when you want “up to the first five” or “everything from this point onward” without first calculating the exact final index.
Slicing also returns a list, even when the range selects only one element or no elements. That differs from ordinary indexing, which returns the individual element itself. The deeper consequences of creating another list value will become important in Lesson 8 on references and copying.
Membership asks whether a value exists
Sometimes you do not need to know where an item is. You only need to know whether the list contains it. The in operator returns the Boolean value True when a match exists and False when it does not. The not in operator expresses the opposite test.
tools = ["camera", "tripod", "lens"]
print("tripod" in tools)
print("flash" in tools)
print("flash" not in tools)
True
False
True
Membership testing compares the requested value with the elements in the list. For strings, matching is case-sensitive: "Tripod" and "tripod" are different strings. The result is Boolean, which means it can be used directly in an if condition rather than compared with True manually.
Membership is especially useful before removal or branching
In Lesson 5, calling remove() with a value that is absent raised ValueError. Membership testing gives you one direct way to check first: if value in items:. It is also useful for feature flags, allowed choices, command lists, simple validation, and any branch where the decision is based on whether a collection includes a value.
Do not overcomplicate the idea. in answers one question: does this collection contain a matching value? If you need the position of that value, you need a different operation. If you need to know how many times it appears, that is another question again.
Slices and membership can work together
Because a slice is itself a list, you can perform membership tests on just that selected portion. This allows a program to ask more specific questions such as “Does this value appear in the first three entries?” without searching the entire original collection.
scores = [72, 85, 91, 64, 88, 95]
top_three = scores[:3]
print(top_three)
print(91 in top_three)
print(95 in top_three)
[72, 85, 91]
True
False
The value 95 exists in the original list but not in the selected first three positions. That distinction demonstrates why the order of operations matters: the program first creates a subset and then asks a membership question about that subset.
items[1:4]Includes index 1 through index 3; stop index 4 is excluded.
items[::2]Uses a step of two across the sequence.
value in itemsReturns True when a matching element exists.
value not in itemsReturns True when no matching element exists.
Common mistakes with slices and membership
The examples below were executed to capture real Python tracebacks. They show that slice boundaries and membership operands still have type requirements even though the syntax is compact.
items = ["a", "b", "c", "d"]
print(items[1.5:3])
Traceback (most recent call last):
File "/tmp/awm_lesson7/mistake1_slice_index_float.py", line 2, in <module>
print(items[1.5:3])
~~~~~^^^^^^^
TypeError: slice indices must be integers or None or have an __index__ method
Slice positions are based on sequence indexes, so ordinary floating-point numbers such as 1.5 are not valid boundaries. If a calculated boundary is not already an integer, your program needs an explicit rule for converting it.
items = ["a", "b", "c", "d"]
print(items[::0])
Traceback (most recent call last):
File "/tmp/awm_lesson7/mistake2_zero_step.py", line 2, in <module>
print(items[::0])
~~~~~^^^^^
ValueError: slice step cannot be zero
A step tells Python how far to move between selections. A step of zero would never move to another position, so Python rejects it. Positive steps move forward; negative steps move backward.
count = 42
print(4 in count)
Traceback (most recent call last):
File "/tmp/awm_lesson7/mistake3_membership_on_int.py", line 2, in <module>
print(4 in count)
^^^^^^^^^^
TypeError: argument of type 'int' is not iterable
The right side of in must support a membership search. A list does; a plain integer does not. If you wanted to know whether the digit 4 appears in the written form of 42, you would first be asking a string question rather than a list-membership question.
items = ["a", "b", "c"]
print(items in "abc")
Traceback (most recent call last):
File "/tmp/awm_lesson7/mistake4_bad_membership_expression.py", line 2, in <module>
print(items in "abc")
^^^^^^^^^^^^^^
TypeError: 'in <string>' requires string as left operand, not list
Read membership expressions from left to right: “Is this value in this collection?” Here the left side is an entire list while the right side is a string. If you meant to ask whether "a" is in the list, write "a" in items.
Supporting classroom explanations
This page is original A Wandering Mind instructional material. The two CPSC 1301K lectures below reinforce the slice syntax and the membership operators used throughout the lesson.
What it adds: a classroom walkthrough of selecting ranges from lists and interpreting the start and stop positions in slice notation.
What it adds: a concise explanation of using in and not in to turn a list search into a Boolean result.
Try it yourself
Predict each result before running the code. For slices, identify the indexes first. For membership tests, read the expression aloud as “Is this value in this collection?”
Exercise 1 · Select the middle three
Create days = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]. Slice out Tuesday through Thursday and print the result.
Show one answer
days = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
middle = days[1:4]
print(middle)
['Tue', 'Wed', 'Thu']
Exercise 2 · Reverse a short list
Create levels = [1, 2, 3, 4]. Use slicing to print the values in reverse order without changing the original variable first.
Show one answer
levels = [1, 2, 3, 4]
print(levels[::-1])
print(levels)
[4, 3, 2, 1]
[1, 2, 3, 4]
Exercise 3 · Check an allowed choice
Create allowed = ["save", "load", "quit"] and command = "load". Use membership in an if statement to print Command accepted. when the command is present.
Show one answer
allowed = ["save", "load", "quit"]
command = "load"
if command in allowed:
print("Command accepted.")
Command accepted.
What you should carry into Lesson 8
You now know how to select more than one position at a time with start:stop:step slicing and how to ask whether a value appears in a list with in or not in. The start of a slice is included, the stop is excluded, and a nonzero step controls the movement between selected positions. Membership returns a Boolean rather than an index.
The next lesson looks beneath the surface of list variables. Continue to References, Aliasing, and Copying Lists to understand why two variable names can sometimes point to the same mutable list—and why a slice can matter when you want a separate outer list.
