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.
strCharacters in quotes.
'hello'listValues in square brackets, separated by commas.
[10, 4.5, 'hi']tupleValues in round brackets — parentheses — separated by commas.
(100, 4.25, 'hi')[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.
word = 'hello'
marks = [10, 4.5, 'hi']
point = (100, 4.25, 'hi')
print(len(word))
print(len(marks))
print(len(point))5 3 3
'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.
[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:
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])P N 4.5 hi P
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.'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.
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['Ravi', 'Meera', 'Amit'] Ravi R t
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.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]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:
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 -1First, 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.
-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.
s = 'good morning'
print(s[2:9:2])o on
s = 'good morning'
print(s[1:6])
print(s[1:7])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.
| start missing | 0 | the first item |
| stop missing | len(s) | run past the last item |
| start missing | -1 | the LAST item |
| stop missing | -len(s) - 1 | run past the first item |
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])ood m omng go girm nr o
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.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:
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])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.
292Python 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:
- 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:
- missing start →
0(the first item) - missing stop →
the end
- missing start →
the LAST item - missing stop →
before the first
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])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:
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 proof0
[::-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.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.
greeting = 'hi' + 'hello'
numbers = [2, 3, 4] + [7.5, -3, 'hello']
pairs = (20, 40) + ('hi', 'bye')
print(greeting)
print(numbers)
print(pairs)hihello [2, 3, 4, 7.5, -3, 'hello'] (20, 40, 'hi', 'bye')
'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.
chant = 'hi' * 3
numbers = [1, 2, 3] * 3
print(chant)
print(numbers)
print((1, 2, 'hi') * 2)hihihi [1, 2, 3, 1, 2, 3, 1, 2, 3] (1, 2, 'hi', 1, 2, 'hi')
'-' * 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 sequenceTrue or Falseword = '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)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.
word = 'hello'
marks = [10, 20, 30]
print('z' not in word)
print('e' not in word)
print(50 not in marks)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.
The letters must sit together and in order. So 'hlo' in 'hello' is False — those letters are scattered.
The list holds two items, and neither of them is 'h'. Python does not look inside an item.
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])True False False True False
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.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
9Recap
| Feature | You write | You get |
|---|---|---|
| Length | len('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 |
True or False. Whether the original could be edited at all is the next lesson.What is 'PYTHON'[1:4]?
How do you reach the LAST character of a string, without knowing its length?
What does 'hi' * 3 give?
'PYTHON'[1:4] gives 'YTH'. What must you write to get 'YTHO' as well?
Why does [::-1] reverse a sequence?
len('hello') is 5. So what is 'hello'[5]?
school = ['Class 11', ['Ravi', 'Meera'], 3]. What is school[1][1][0]?
What does 'h' in ['hi', 'bye'] give?
Which of these is True?