LambdaLabTM
Computer Science · Class 11 · Data Types
Data TypesSequences⏱️ 13 min read

Common Features of Sequences

The Sequential family had three members: string, list and tuple. They look nothing alike — quotes, square brackets, round brackets. But they share six tricks, and once you learn the six on a string, you already know them on the other two.

1What is a sequence?

A sequence is a collection of items kept in order, one after another. That order is the whole point: the items have positions, and the positions never wander about on their own.

str
string

Characters in quotes.

'hello'
5 characters
list
list

Values in square brackets, separated by commas.

[10, 4.5, 'hi']
3 elements
tuple
tuple

Values in round brackets — parentheses — separated by commas.

(100, 4.25, 'hi')
3 elements
Note
A list can hold mixed types — a number, a float and a string all together, as in [10, 4.5, 'hi']. So can a tuple. A string holds only characters. Lists and tuples get their own lessons later; here we only care about what all three have in common.

21 · len() — how many items?

len() is your third function. (A word, then parentheses — you know the drill.) Give it a sequence and it tells you how many items are inside: characters for a string, elements for a list or a tuple.

how_many.py
word = 'hello'
marks = [10, 4.5, 'hi']
point = (100, 4.25, 'hi')

print(len(word))
print(len(marks))
print(len(point))
Output
5
3
3
Tip
Count carefully: 'hello' has 5 characters, so len is 5. But the last character sits at position 4, not 5 — because positions start at 0. That gap of one is the source of a great many exam mistakes, and the next section is about it.

32 · Indexing — reaching one item

Every item in a sequence has a position, also called its index. You reach an item by writing its index inside square brackets after the sequence.

And there are two kinds of index. Positive indexes count from the left and start at 0. Negative indexes count from the right and start at -1. Tap any letter below — it has both.

Tap a letter — it has two addresses
0
1
2
3
4
5
-6
-5
-4
-3
-2
-1
↑ positive: counts from 0↓ negative: counts from the end
Every letter has a positive address and a negative one. Both point at the same letter.
Key Takeaway
The first item is [0], never [1]. The last item is [-1] — and that is the real reason negative indexing exists: reaching the end without having to know how long the thing is.

Indexing works the same way on all three sequence types:

reaching_one.py
word = 'PYTHON'
marks = [10, 4.5, 'hi']
point = (100, 4.25, 'hi')

print(word[0])
print(word[-1])
print(marks[1])
print(point[-1])

# you can index a value directly too, without a variable
print('PYTHON'[0])
Output
P
N
4.5
hi
P
Tip
Look at the output: P, not 'P'. print() drops the quotes, just as it did in the print lesson. The quotes only tell Python where the text starts and ends.
Watch Out
Ask for a position that does not exist and Python stops with an IndexError. 'PYTHON'[99] gives IndexError: string index out of range — there is no position 99, and Python will not invent one.

Sometimes the item you reach is itself a sequence — a list can hold another list, and that inner list can hold a string. Then you index again, with a second pair of brackets. And a third, if you want one character out of that string.

index_inside_index.py
school = ['Class 11', ['Ravi', 'Meera', 'Amit'], 3]

print(school[1])          # a list lives at position 1
print(school[1][0])       # position 0 of THAT list — a string
print(school[1][0][0])    # position 0 of THAT string — one character
print(school[1][-1][-1])  # last name, last character
Output
['Ravi', 'Meera', 'Amit']
Ravi
R
t
Key Takeaway
school[1][0][0] is not one special three-part index. It is three ordinary indexes, done left to right: school[1] gives the inner list, [0] gives 'Ravi' out of that list, and the last [0] gives 'R' out of that string. Read the brackets one at a time and ask what you are holding after each one.
Tip
Each pair of brackets must make sense for what you are holding at that moment. school[0][0] is fine — 'Class 11' is a string, so it has a position 0, which is 'C'. But school[2][0] stops the program with TypeError: 'int' object is not subscriptable 3 is a number, and a number has no positions inside it to reach.

43 · Slicing — taking a piece

Indexing gives you one item. Slicing gives you a piece — several items at once. The full form has three parts, separated by colons:

sequence[start : stop : step]
start — where to begin (this one is included)
stop — where to end (this one is NOT included)
step — how big a jump each time

Slicing is the process of getting a new sequence out of an existing one. For the rest of this section we will use one string, and both of its rulers:

slicing.py
s = 'good morning'

#    g  o  o  d     m  o  r  n  i  n  g
#    0  1  2  3  4  5  6  7  8  9 10 11
#  -12-11-10 -9 -8 -7 -6 -5 -4 -3 -2 -1

First, the step

You do not have to write all three parts. Settle the step first, because it is the easy one. If you do not write a step, Python uses 1.

Key Takeaway
A missing step is always 1. It is never -1. To go backwards you must type the minus sign yourself, like s[::-1] or s[8:2:-2]. No minus sign means you are going forwards.

So s[1:6] and s[1:6:1] mean the same thing. Any slice below with only two parts moves forwards, one item at a time.

start is included. stop is excluded.

This is the rule that costs marks every single year. In s[2:9:2], the walk starts at 2 and jumps in twos — 2, 4, 6, 8 — and it must stop before 9.

slicing.py
s = 'good morning'

print(s[2:9:2])
Output
o on
Watch Out
So how do I include the stop position? You ask for one more than you want. If you want position 5 in the result, write the stop as 6. The stop is a fence you halt before, not the last item you take.
slicing.py
s = 'good morning'

print(s[1:6])
print(s[1:7])
Output
ood m
ood mo

A neat side effect (when the step is 1): stop − start is exactly how many items you get. [1:6] gives 6 − 1 = 5 characters. No counting on fingers.

What if you leave a part out?

Every part is optional. When you leave one out, Python fills it in for you. You already know the first rule: a missing step is 1.

That leaves the start and the stop. And here is the part most books skip: what Python fills in for those two depends on the direction of the step. So read the box that matches your step.

➡️ step is positive (walking forwards)
start missing0the first item
stop missinglen(s)run past the last item
⬅️ step is negative (walking backwards)
start missing-1the LAST item
stop missing-len(s) - 1run past the first item
slicing.py
s = 'good morning'

print(s[1:6])     # step missing  -> same as s[1:6:1]
print(s[2::3])    # stop missing  -> same as s[2:len(s):3]
print(s[:6:2])    # start missing -> same as s[0:6:2]
print(s[:3:-2])   # start missing, step -ve -> same as s[-1:3:-2]
print(s[-2::-3])
Output
ood m
omng
go 
girm
nr o
Tip
Look at the third line of that output: go and then a space. The space between good and morning sits at position 4, so the jumps 0 → 2 → 4 pick it up. A space is a character like any other. You just cannot see it on screen.
Watch Out
A question worth two minutes. When the step is positive, why is the missing stop len(s) and not -1? And when the step is negative, why is it -len(s) - 1 and not 0?

Because the stop is excluded — so the stop must land on a position that does not exist. Watch what goes wrong otherwise:

why_past_the_edge.py
s = 'good morning'

# If the default stop were -1 (the LAST character) — the final 'g' is lost:
print(s[0:-1])

# If the default stop were 0 (the FIRST character) — the first 'g' is lost:
print(s[-1:0:-1])
Output
good mornin
gninrom doo

Both are real positions, so excluding them chops a character off the end of your answer. Python instead stops at a position just past the edge — one that no character occupies — so nothing is lost.

Play with all three below. The panel shows you exactly what Python filled in for the parts you left blank — and the little numbers under the letters show the order it visits them in.

start : stop : step
start2
stop9
step2
0
1
2
3
4
5
6
7
8
9
10
11
g
o
o1
d
2
m
o3
r
n4
i
n
g
-12
-11
-10
-9
-8
-7
-6
-5
-4
-3
-2
-1
the small numbers show the order Python visits them in
What Python fills in for what you left out
start = 2stop = 9step = 2
>>> 'good morning'[2:9:2]
'o on'

Python starts at start, jumps by step each time, and stops before stop.

Why [::-1] reverses anything

This is the famous one, and it looks like a magic spell. It is not — you have already learnt every piece of it. Set the step to -1 in the widget above and read the “what Python fills in” panel.

In s[::-1] you gave Python only the step: -1, meaning walk backwards, one at a time. So it fills in the other two from the rules above:

s[::-1]  →  s[-1 : -len(s)-1 : -1]
  • start = -1 → begin at the last character
  • stop = just past the first character → so nothing is left out
  • step = -1 → move backwards, one at a time

Begin at the end, walk backwards, stop only after passing the start. That is a reversal — and no reversing function was needed to get it.

The same reasoning is why the defaults must flip for a negative step. Starting at position 0 and walking backwards would fall off the front immediately, and you would get nothing at all:

Step is positive (forwards)
  • missing start → 0 (the first item)
  • missing stop → the end
Step is negative (backwards)
  • missing start → the LAST item
  • missing stop → before the first
reversing.py
s = 'good morning'
print(s[::-1])

# a slice does not need a variable — you can slice a value where it stands
print([1, 2, 3][::-1])
print((1, 2, 3)[::-1])
Output
gninrom doog
[3, 2, 1]
(3, 2, 1)

And watch a slice go the wrong way and return nothing at all — no error, just an empty result. s[4:-2:-2] asks to start at 4 and walk backwards to position 10. You cannot walk backwards from 4 and arrive at 10, so Python hands back an empty string:

empty_slice.py
s = 'good morning'

nothing = s[4:-2:-2]

print(nothing)        # an empty line — there is nothing to show
print(len(nothing))   # and here is the proof
Output

0
Key Takeaway
[::-1] reverses any sequence — string, list or tuple — because slicing is a sequence feature, not a string feature. And notice what comes back each time: a string gives a string, a list gives a list, a tuple gives a tuple. A slice always hands you back the same type you sliced.
Tip
A slice never raises an error, even when you ask for too much. s[2:100] quietly gives 'od morning', and s[99:] gives an empty string ''. Indexing is strict — it raises an IndexError. Slicing is forgiving.

54 · Concatenation — joining with +

Concatenation means joining two sequences end to end with + to make one new sequence. You have already seen + add two numbers. On sequences it does something else entirely: it joins.

joining.py
greeting = 'hi' + 'hello'
numbers = [2, 3, 4] + [7.5, -3, 'hello']
pairs = (20, 40) + ('hi', 'bye')

print(greeting)
print(numbers)
print(pairs)
Output
hihello
[2, 3, 4, 7.5, -3, 'hello']
(20, 40, 'hi', 'bye')
Watch Out
Both sides must be the same type. A string joins to a string, a list to a list. Mix them and Python refuses: 'hi' + 5 gives TypeError: can only concatenate str (not "int") to str. There is no space added for you either — 'hi' + 'hello' is 'hihello', not 'hi hello'.

65 · Replication — repeating with *

Replication (also called repetition) means repeating a sequence a given number of times, using * and a whole number. Again, a brand new sequence comes back.

repeating.py
chant = 'hi' * 3
numbers = [1, 2, 3] * 3

print(chant)
print(numbers)
print((1, 2, 'hi') * 2)
Output
hihihi
[1, 2, 3, 1, 2, 3, 1, 2, 3]
(1, 2, 'hi', 1, 2, 'hi')
Tip
Handy trick: '-' * 30 draws you a neat line of 30 dashes for a heading. Try it below.

76 · Membership — in and not in

The last shared trick answers one question: is this thing inside that sequence? Write in between the two. The answer is always True or False. It does not tell you where the item is, only whether it is there.

item in sequence
True or False
membership.py
word = 'hello'
marks = [10, 20, 30]
point = (100, 4.25, 'hi')

print('e' in word)
print('z' in word)
print(20 in marks)
print('hi' in point)
Output
True
False
True
True

not in is its opposite, and it is two words, not not-in or notin. It gives True when the item is missing.

membership.py
word = 'hello'
marks = [10, 20, 30]

print('z' not in word)
print('e' not in word)
print(50 not in marks)
Output
True
False
True

The one place strings behave differently

On a list or a tuple, in checks whole items only. On a string it also finds a piece of the text, even part of a word. Compare these two carefully — this is the exam question.

String — pieces count
'ell' in 'hello' → True
'lo' in 'hello' → True

The letters must sit together and in order. So 'hlo' in 'hello' is False — those letters are scattered.

List / tuple — whole items only
'hi' in ['hi', 'bye'] → True
'h' in ['hi', 'bye'] → False

The list holds two items, and neither of them is 'h'. Python does not look inside an item.

pieces_vs_items.py
word = 'hello'
words = ['hi', 'bye']

print('ell' in word)     # a piece of the text — found
print('hlo' in word)     # those letters are scattered
print('h' in words)      # the list holds 'hi' and 'bye', not 'h'
print(30 in [10, 20, 30])
print(3 in [10, 20, 30])
Output
True
False
False
True
False
Key Takeaway
in and not in always hand back True or False — so they belong in an if. if '@' in email: reads almost like English, and that is the whole point of them.
Watch Out
You will meet the word in again in a for loop — for ch in 'hello':. Same word, different job. There it means go through each item; here it asks a question and gives an answer. The loops chapter will make the difference obvious.

8Try all six at the prompt

Python prompt — interactive mode
# Everything from this lesson works here. Try a slice, a join, a repeat, a membership check.
>>>
try

9Recap

FeatureYou writeYou get
Lengthlen('hello')5
Indexing (positive)'PYTHON'[0]'P'
Indexing (negative)'PYTHON'[-1]'N'
Indexing (one inside another)['hi', ['abc', 'de']][1][0][2]'c'
Slicing'PYTHON'[1:4]'YTH' — stop is left out
Concatenation'hi' + 'hello''hihello'
Replication'hi' * 3'hihihi'
Membership'T' in 'PYTHON'True
Membership (not)'z' not in 'PYTHON'True
Key Takeaway
All six work on strings, lists and tuples alike — that is what makes them the common features. And not one of them edits the original: five hand you back a new value, and membership hands you back True or False. Whether the original could be edited at all is the next lesson.
Quick Check

What is 'PYTHON'[1:4]?

Quick Check

How do you reach the LAST character of a string, without knowing its length?

Quick Check

What does 'hi' * 3 give?

Quick Check

'PYTHON'[1:4] gives 'YTH'. What must you write to get 'YTHO' as well?

Quick Check

Why does [::-1] reverse a sequence?

Quick Check

len('hello') is 5. So what is 'hello'[5]?

Quick Check

school = ['Class 11', ['Ravi', 'Meera'], 3]. What is school[1][1][0]?

Quick Check

What does 'h' in ['hi', 'bye'] give?

Quick Check

Which of these is True?