Class 11Computer Science · Programming with PythonFull chapter

Tuples and Dictionaries

The whole chapter in one place — read it, then test yourself. Clear notes, a reference sheet, a practice quiz, and worked NCERT solutions & PYQs.

Tuples: Creating, Indexing and Immutability

Quick answer A tuple is an ordered, indexed collection that cannot be changed after it is created — and the comma, not the bracket, is what actually makes one.

A tuple is an ordered collection of values written inside round brackets and separated by commas. It behaves almost exactly like a list, with one hard difference: once a tuple exists you cannot change it. You cannot replace an item, add an item or delete an item. This property is called immutability.

Why would anyone want a container you cannot edit? Because a lot of real data should not change. The PNR and date of travel on an IRCTC ticket, the (latitude, longitude) of a school, the fixed order of the twelve months, one printed row of a marksheet — if a stray line of code overwrites one of these, the bug is silent and expensive. A tuple simply refuses the edit, so the accident cannot happen.

1. Creating a tuple

marks = (78, 92, 65, 88, 71)
print(marks)
print(type(marks))

empty = ()
print(empty, type(empty), len(empty))

# single element - the classic trap
a = (5)
b = (5,)
print(a, type(a))
print(b, type(b))
print(len(b))

# parentheses are optional
student = "Aarav", 11, "CS"
print(student, type(student))

Real output:

(78, 92, 65, 88, 71)

()  0
5 
(5,) 
1
('Aarav', 11, 'CS') 

Look hard at lines 4 and 5. (5) is not a tuple — it is just the integer 5 with a pair of ordinary brackets round it, exactly like (2 + 3) in maths. What creates a tuple is the comma, not the bracket. So a one-element tuple must be written (5,). This trailing comma looks like a typing mistake but it is compulsory, and it is asked in the board exam almost every year.

The last line shows the other side of the same rule: because the comma does the work, the brackets can be dropped altogether. "Aarav", 11, "CS" is already a tuple.

2. Indexing

Items are numbered from 0 from the left and from -1 from the right, exactly as in strings and lists.

subjects = ('English', 'Physics', 'Chemistry', 'Maths', 'CS')
print(subjects[0])
print(subjects[4])
print(subjects[-1])
print(subjects[-5])

Real output:

English
CS
CS
English

Ask for an index that does not exist and the program stops with a run-time error:

subjects = ('English', 'Physics', 'Chemistry', 'Maths', 'CS')
print(subjects[5])

Real output:

Traceback (most recent call last):
  File "demo.py", line 2, in 
    print(subjects[5])
          ~~~~~~~~^^^
IndexError: tuple index out of range

A tuple of 5 items has valid indexes 0 to 4 and -1 to -5. Anything else is an IndexError.

3. Immutability, shown as an actual error

prices = (250, 499, 120)
prices[0] = 300

Real output:

Traceback (most recent call last):
  File "demo.py", line 2, in 
    prices[0] = 300
    ~~~~~~^^^
TypeError: 'tuple' object does not support item assignment

The tuple refused the edit and the program stopped. What you can do is build a brand-new tuple out of the old one:

prices = (250, 499, 120)
prices = prices + (999,)
print(prices)

Real output:

(250, 499, 120, 999)

Learn that error message word for word. And notice what the second program does not do: it does not modify the tuple. prices + (999,) built a brand-new tuple and the name prices was pointed at it. The original object was never touched — it was simply abandoned.

4. The tuple() function

print(tuple("UPI"))
print(tuple([10, 20, 30]))
print(tuple(range(1, 6)))
print(tuple())

Real output:

('U', 'P', 'I')
(10, 20, 30)
(1, 2, 3, 4, 5)
()

tuple() converts any sequence — a string, a list or a range — into a tuple, and tuple() with nothing inside it gives the empty tuple. A plain number is not a sequence, so there is nothing to convert:

print(tuple(45))

Real output:

Traceback (most recent call last):
  File "demo.py", line 1, in 
    print(tuple(45))
          ~~~~~^^^^
TypeError: 'int' object is not iterable

5. Nested tuples

A tuple can hold other tuples. This is how you store a table — one inner tuple per row.

result = (('Aarav', 87), ('Diya', 91), ('Kabir', 78))
print(result[1])
print(result[1][0])
print(result[1][1])
print(len(result))

# a mutable object inside an immutable tuple
t = (1, [2, 3], 4)
t[1].append(99)
print(t)

Real output:

('Diya', 91)
Diya
91
3
(1, [2, 3, 99], 4)

Changing what is inside the list worked. Swapping the list itself for a different object is still blocked:

t = (1, [2, 3], 4)
t[1] = [7, 8]

Real output:

Traceback (most recent call last):
  File "demo.py", line 2, in 
    t[1] = [7, 8]
    ~^^^
TypeError: 'tuple' object does not support item assignment

len(result) is 3, not 6 — len() counts only the top level. The t = (1, [2, 3], 4) half is a favourite trick question. The tuple t is immutable, but the list stored inside it is not. You cannot swap the list for a different object, yet you can change the contents of that list. The tuple only promises "the same three objects, in this order, forever" — it makes no promise about what is inside those objects.

6. List versus tuple

PointListTuple
Brackets[ ]( )
ChangeableYes (mutable)No (immutable)
append / remove / sortAvailableNot available
MethodsExactly 11Only 2: count(), index()
Can be a dictionary keyNoYes
Use it forData that grows or changesFixed records and constants
Tuple literal t = (v1, v2, v3) tuple · Ordered and immutable. Brackets optional: t = v1, v2, v3 works too.
Single-element tuple t = (5,) The trailing comma is compulsory. (5) is an int; len((5)) raises TypeError: object of type 'int' has no len().
Empty tuple t = () or t = tuple() len(t) is 0. There is no comma to add.
tuple() tuple(iterable) -> tuple Converts a string, list or range. tuple(45) -> TypeError: 'int' object is not iterable.
Indexing t[i] / t[-i] 0 to n-1 from the left, -1 to -n from the right. Out of range -> IndexError.
Immutability t[i] = x -> TypeError 'tuple' object does not support item assignment. Rebinding t = t + (x,) is fine — it makes a new tuple.
Remember
  • The comma makes a tuple, not the brackets: (5) is an int, (5,) is a one-item tuple, and x = 1, 2 is a tuple with no brackets at all.
  • Assigning to an item gives TypeError: 'tuple' object does not support item assignment. Building a new tuple with + is allowed because it does not modify the old one.
  • Indexes run 0 to n-1 and -1 to -n; anything outside gives IndexError: tuple index out of range.
  • len() counts only the top level of a nested tuple, so len((('a',1),('b',2))) is 2.
  • A list stored inside a tuple can still be modified — the tuple freezes which objects it holds, not what is inside them.

Tuple Operations: +, *, in, Slicing and Tuple Assignment

Quick answer Concatenation, repetition, membership and slicing all build new tuples rather than editing the old one, while tuple assignment unpacks a record into separate variables in a single line.

Because a tuple can never be edited, every operation here returns a new tuple and leaves the original alone. Keep that sentence in your head and half the output questions answer themselves.

1. Concatenation (+) and repetition (*)

sec_a = ('Aarav', 'Diya')
sec_b = ('Kabir', 'Meera')
print(sec_a + sec_b)
print(sec_a)

print(('OK',) * 3)
print((0,) * 5)
print(sec_a * 0)

Real output:

('Aarav', 'Diya', 'Kabir', 'Meera')
('Aarav', 'Diya')
('OK', 'OK', 'OK')
(0, 0, 0, 0, 0)
()

sec_a is unchanged after the + — a third tuple was created and both originals are exactly as they were. Multiplying by 0 or a negative number gives an empty tuple, and (0,) * 5 is the standard way to make a fixed-size tuple of zeros.

+ also refuses to mix types. A tuple can only be joined to another tuple, never to a list:

sec_a = ('Aarav', 'Diya')
print(sec_a + ['Rohit'])

Real output:

Traceback (most recent call last):
  File "demo.py", line 2, in 
    print(sec_a + ['Rohit'])
          ~~~~~~^~~~~~~~~~~
TypeError: can only concatenate tuple (not "list") to tuple

To join the two you must convert one of them first, for example sec_a + tuple(['Rohit']).

2. Membership (in / not in)

subjects = ('English', 'Physics', 'Chemistry', 'Maths', 'CS')
print('Maths' in subjects)
print('Biology' in subjects)
print('Biology' not in subjects)
print('Math' in subjects)

nested = (('Aarav', 87), ('Diya', 91))
print('Aarav' in nested)
print(('Aarav', 87) in nested)

Real output:

True
False
True
False
False
True

in checks for a whole item, never a part of one. 'Math' is not an item of subjects even though 'Maths' starts with it. In a nested tuple the items are the inner tuples, so 'Aarav' in nested is False but ('Aarav', 87) in nested is True.

3. Slicing

The rule is t[start : end : step]. start is included, end is excluded.

t = (10, 20, 30, 40, 50, 60, 70)
print(t[1:4])
print(t[:3])
print(t[4:])
print(t[:])
print(t[-3:])
print(t[1:6:2])
print(t[::-1])
print(t[5:2])
print(t[5:2:-1])

Real output:

(20, 30, 40)
(10, 20, 30)
(50, 60, 70)
(10, 20, 30, 40, 50, 60, 70)
(50, 60, 70)
(20, 40, 60)
(70, 60, 50, 40, 30, 20, 10)
()
(60, 50, 40)

Slicing never raises an error, even for nonsense ranges — t[5:2] quietly returns an empty tuple because you cannot walk forwards from index 5 to index 2. Add a negative step and the same range works: t[5:2:-1] walks backwards. t[::-1] is the standard reverse idiom.

4. Comparing tuples

print((1, 2, 3) == (1, 2, 3))
print((1, 2, 3) < (1, 2, 4))
print((1, 20) < (2, 1))
print(('Aarav',) < ('Diya',))
print((1, 2) < (1, 2, 0))

Real output:

True
True
True
True
True

Comparison works item by item from the left, like dictionary order for words. Python compares 1 with 2 first; since 1 is smaller, (1, 20) < (2, 1) is True and the 20 is never even looked at. If one tuple runs out of items first, the shorter one is smaller.

5. Tuple assignment (unpacking)

student = ('Aarav Sharma', 11, 'CS', 87)
name, cls, stream, marks = student
print(name)
print(cls, stream, marks)

x, y = 5, 9
print(x, y)
x, y = y, x
print(x, y)

first, *rest = (10, 20, 30, 40)
print(first, rest, type(rest))

Real output:

Aarav Sharma
11 CS 87
5 9
9 5
10 [20, 30, 40] 

Offer too few names for the items available and Python stops:

student = ('Aarav Sharma', 11, 'CS', 87)
p, q = student

Real output:

Traceback (most recent call last):
  File "demo.py", line 2, in 
    p, q = student
    ^^^^
ValueError: too many values to unpack (expected 2)

Ask for more names than there are items and you get the mirror-image message:

t = (10, 20, 30)
a, b, c, d = t

Real output:

Traceback (most recent call last):
  File "demo.py", line 2, in 
    a, b, c, d = t
    ^^^^^^^^^^
ValueError: not enough values to unpack (expected 4, got 3)

The number of names on the left must exactly match the number of items on the right, otherwise you get a ValueError. The swap x, y = y, x works because the right-hand side is packed into the tuple (9, 5) first, and only then unpacked — so no temporary variable is needed. Note that the starred name rest collects into a list, not a tuple.

Worked example — one IRCTC booking record

booking = ('2841567390', 'Aarav Sharma', 24, 'M', 'S4', 42, 1245)
pnr, name, age, gender, coach, berth, fare = booking
print("PNR   :", pnr)
print("Name  :", name, "| Age:", age, "| Gender:", gender)
print("Seat  :", coach + "-" + str(berth))
print("Fare  : Rs.", fare)
print("Masked PNR:", "*" * 6 + pnr[-4:])
print("Travel bit:", booking[4:6])
print("Reversed  :", booking[::-1])

group = (booking, ('2841567390', 'Diya Nair', 22, 'F', 'S4', 43, 1245))
print("Passengers:", len(group))
total = 0
for rec in group:
    print(" ", rec[1], "->", rec[4] + "-" + str(rec[5]))
    total = total + rec[6]
print("Total fare: Rs.", total)

Real output:

PNR   : 2841567390
Name  : Aarav Sharma | Age: 24 | Gender: M
Seat  : S4-42
Fare  : Rs. 1245
Masked PNR: ******7390
Travel bit: ('S4', 42)
Reversed  : (1245, 42, 'S4', 'M', 24, 'Aarav Sharma', '2841567390')
Passengers: 2
  Aarav Sharma -> S4-42
  Diya Nair -> S4-43
Total fare: Rs. 2490

A booking is exactly the kind of data a tuple is for: it has a fixed shape, and nothing in it should change after the ticket is issued. Unpacking in the for header also works — for name, score in marks: pulls both fields out of each inner tuple in one line.

Concatenation t1 + t2 -> tuple Both sides must be tuples. Returns a NEW tuple; t1 is unchanged.
Repetition t * n -> tuple n (0, 0, 0, 0, 0).
Membership x in t / x not in t -> bool Whole-item match only. Never matches a part of an item.
Slicing t[start:end:step] -> tuple start included, end excluded. Out-of-range is safe and returns (). t[::-1] reverses.
Tuple assignment a, b, c = t Count must match exactly, else ValueError: too many / not enough values to unpack.
Swap x, y = y, x Right side is packed into a tuple first, then unpacked. No temp variable needed.
Remember
  • + and * build a new tuple; the originals are untouched. Tuple + list is a TypeError, not a merge.
  • in matches a complete item only — 'Math' in ('Maths',) is False, and in a nested tuple the items are the inner tuples.
  • Slicing never errors: a bad range like t[5:2] silently returns (). t[::-1] reverses.
  • Tuple comparison is left-to-right, item by item; the first difference decides, and a shorter tuple that matches so far is smaller.
  • Unpacking needs an exact count match or it raises ValueError: too many values to unpack; x, y = y, x swaps without a temporary variable.

Built-in Functions, Methods and the Three Classic Tuple Programs

Quick answer len(), min(), max(), sum(), sorted(), count() and index() are the whole toolkit for tuples, and they are enough to write the minimum/maximum/mean, linear search and frequency programs named in the syllabus.

A tuple has only two methods, count() and index(), because every other list method would have to change the tuple. Everything else is a built-in function that you pass the tuple to.

1. The whole toolkit in one run

marks = (78, 92, 65, 88, 71, 92)
print(len(marks))
print(min(marks), max(marks), sum(marks))
print(sorted(marks))
print(sorted(marks, reverse=True))
print(marks)
print(type(sorted(marks)))
print(tuple(sorted(marks)))

names = ('Aarav', 'diya', 'Kabir')
print(min(names), max(names))
print(sorted(names))

print(marks.count(92), marks.count(100))
print(marks.index(92))
print(sum(marks, 10))

Real output:

6
65 92 486
[65, 71, 78, 88, 92, 92]
[92, 92, 88, 78, 71, 65]
(78, 92, 65, 88, 71, 92)

(65, 71, 78, 88, 92, 92)
Aarav diya
['Aarav', 'Kabir', 'diya']
2 0
1
496

Six things worth marking in your notes:

  • sorted() always returns a list, even when you give it a tuple. If you need a tuple back, wrap it: tuple(sorted(marks)).
  • sorted() does not touch the original — the fifth line prints the unsorted tuple. There is no marks.sort(), because that would modify the tuple.
  • count() of a missing value is 0 and is always safe. index() of a missing value raises ValueError. So check with in or count() before calling index().
  • index() returns the first position only. 92 appears at index 1 and index 5; you get 1.
  • min() and max() on strings compare by ASCII/Unicode code, so every capital letter is smaller than every small letter. That is why 'diya' is the maximum and why sorted() puts it last.
  • sum() works only on numbers. sum(t, start) adds an optional starting value — 486 + 10 = 496.

Two of these stop the program if you misuse them. Asking index() for a value the tuple does not contain is a run-time error:

marks = (78, 92, 65, 88, 71, 92)
print(marks.index(100))

Real output:

Traceback (most recent call last):
  File "demo.py", line 2, in 
    print(marks.index(100))
          ~~~~~~~~~~~^^^^^
ValueError: tuple.index(x): x not in tuple

And sum() only knows how to add numbers:

names = ('Aarav', 'diya', 'Kabir')
print(sum(names))

Real output:

Traceback (most recent call last):
  File "demo.py", line 2, in 
    print(sum(names))
          ~~~^^^^^^^
TypeError: unsupported operand type(s) for +: 'int' and 'str'

2. Worked example — a marksheet report

subjects = ('English', 'Physics', 'Chemistry', 'Maths', 'CS')
marks    = (78, 92, 65, 88, 71)

print("Subject      Marks")
for i in range(len(subjects)):
    print(subjects[i].ljust(12), marks[i])

total = sum(marks)
print("Total   :", total, "/", len(marks) * 100)
print("Percent :", round(total / len(marks), 2), "%")
print("Best    :", subjects[marks.index(max(marks))], "-", max(marks))
print("Weakest :", subjects[marks.index(min(marks))], "-", min(marks))
print("Sorted  :", sorted(marks, reverse=True))

count = 0
for m in marks:
    if m >= 75:
        count = count + 1
print("75 and above:", count, "subjects")

Real output:

Subject      Marks
English      78
Physics      92
Chemistry    65
Maths        88
CS           71
Total   : 394 / 500
Percent : 78.8 %
Best    : Physics - 92
Weakest : Chemistry - 65
Sorted  : [92, 88, 78, 71, 65]
75 and above: 3 subjects

subjects[marks.index(max(marks))] is the pattern to remember: find the biggest mark, ask which position it sits at, then read the matching subject from the parallel tuple. Two tuples used side by side like this are called parallel tuples.

3. Syllabus program — minimum, maximum and mean

import statistics

marks = (78, 92, 65, 88, 71)
print("Marks      :", marks)
print("Minimum    :", min(marks))
print("Maximum    :", max(marks))
print("Mean (sum) :", sum(marks) / len(marks))
print("Mean (stat):", statistics.mean(marks))
print("Rounded    :", round(sum(marks) / len(marks), 2))

Real output:

Marks      : (78, 92, 65, 88, 71)
Minimum    : 65
Maximum    : 92
Mean (sum) : 78.8
Mean (stat): 78.8
Rounded    : 78.8

Both ways of finding the mean give the same answer. In the exam either is accepted, but write sum(t) / len(t) if the question says "without using any library".

4. Syllabus program — linear search on a tuple

Linear search means: start at index 0 and check every item until you find the target or run out. Use -1 when it is not there, which is the standard "not found" signal.

roll_nos = (1104, 1109, 1112, 1117, 1121, 1125)
target = 1117

pos = -1
for i in range(len(roll_nos)):
    if roll_nos[i] == target:
        pos = i
        break

if pos == -1:
    print(target, "not found")
else:
    print(target, "found at index", pos, "(position", pos + 1, ")")

target = 1150
pos = -1
for i in range(len(roll_nos)):
    if roll_nos[i] == target:
        pos = i
        break
print("Search for", target, "-> index", pos)

Real output:

1117 found at index 3 (position 4 )
Search for 1150 -> index -1

The break matters: without it the loop keeps running after the match and wastes time. Set pos = -1 before the loop, not inside it — a common mistake is to put the initialisation inside and reset it on every turn.

5. Syllabus program — frequency of each element

votes = ('BJP', 'INC', 'BJP', 'AAP', 'INC', 'BJP', 'NOTA', 'AAP', 'BJP')

done = ()
for item in votes:
    if item not in done:
        print(item, "->", votes.count(item))
        done = done + (item,)

Real output:

BJP -> 4
INC -> 2
AAP -> 2
NOTA -> 1

The done tuple stops an item being reported twice. Without it, 'BJP' would print four times. Notice how done = done + (item,) again needs that compulsory trailing comma. This is honest working code, but you will see in the next two sections that a dictionary does the same job in three lines and without repeated scanning — counting is what dictionaries were invented for.

len() len(t) -> int Counts top-level items only. len((('a',1),('b',2))) is 2, not 4.
min() / max() / sum() min(t), max(t), sum(t[, start]) sum() needs numbers — sum(('a','b')) raises TypeError. min/max on strings compare by Unicode code, so 'Z' < 'a'.
sorted() sorted(t, reverse=False) -> list Always returns a LIST, never a tuple. Original tuple unchanged. Wrap in tuple() if needed.
t.count() t.count(x) -> int Number of times x occurs. Returns 0 (never an error) if x is absent.
t.index() t.index(x) -> int Position of the FIRST occurrence. ValueError: tuple.index(x): x not in tuple if missing.
Mean of a tuple sum(t) / len(t) or statistics.mean(t) Both return a float. Use round(value, 2) to print two decimal places.
Remember
  • A tuple has exactly two methods: count() and index(). Everything else — len, min, max, sum, sorted, tuple — is a built-in function.
  • sorted(t) returns a list and leaves t unchanged; use tuple(sorted(t)) to get a tuple back. There is no t.sort().
  • t.count(x) is safe and returns 0 if x is absent, but t.index(x) raises ValueError: tuple.index(x): x not in tuple. index() gives only the first match.
  • Mean = sum(t) / len(t), or statistics.mean(t). Both give 78.8 for (78, 92, 65, 88, 71).
  • Linear search pattern: set pos = -1 before the loop, scan with range(len(t)), and break on the first match.

Dictionaries: Keys, Values, Safe Access and Traversal

Quick answer A dictionary stores key:value pairs, is fully mutable, and gives you two ways to read an item — d[k] which crashes on a missing key and d.get(k) which returns None instead.

A dictionary stores data as key : value pairs inside curly brackets. Instead of asking "what is at position 3?" you ask "what is stored under 'Physics'?". That is the whole idea: a dictionary is indexed by meaningful names, not by numbers.

Think of the marks column of a marksheet, a phone contact list, a UPI ID mapped to a bank account, or a pincode mapped to a city. In every one of these the key is what you already know and the value is what you want to look up.

1. Creating and accessing — and the KeyError question

marks = {'English': 78, 'Physics': 92, 'CS': 88}
print(marks)
print(type(marks), len(marks))

empty = {}
print(empty, type(empty), len(empty))

print(marks['Physics'])
print(marks.get('Physics'))
print(marks.get('Maths'))
print(marks.get('Maths', 0))
print(marks.get('Maths', 'Not offered'))

Real output:

{'English': 78, 'Physics': 92, 'CS': 88}
 3
{}  0
92
92
None
0
Not offered

Now ask for a key that is not there, this time with square brackets:

marks = {'English': 78, 'Physics': 92, 'CS': 88}
print(marks['Maths'])

Real output:

Traceback (most recent call last):
  File "demo.py", line 2, in 
    print(marks['Maths'])
          ~~~~~^^^^^^^^^
KeyError: 'Maths'

This is the most examined difference in the whole chapter, so read it slowly:

  • marks['Maths'] raises KeyError and the program stops.
  • marks.get('Maths') returns None and the program keeps running.
  • marks.get('Maths', 0) returns whatever default you supply instead of None.

Note also that {} creates an empty dictionary — a pair of curly brackets with nothing between them is always a dictionary, never anything else. And len() on a dictionary counts pairs, not individual keys and values — 3 pairs, not 6.

2. Dictionaries are mutable

marks = {'English': 78, 'Physics': 92, 'CS': 88}
marks['Maths'] = 81          # add
print(marks)
marks['Physics'] = 95        # modify
print(marks)
del marks['English']         # delete
print(marks)
print(len(marks))

# duplicate key at creation - last one wins
d = {'a': 1, 'b': 2, 'a': 9}
print(d)

Real output:

{'English': 78, 'Physics': 92, 'CS': 88, 'Maths': 81}
{'English': 78, 'Physics': 95, 'CS': 88, 'Maths': 81}
{'Physics': 95, 'CS': 88, 'Maths': 81}
3
{'a': 9, 'b': 2}

Deleting a key that is not in the dictionary is a run-time error:

marks = {'Physics': 95, 'CS': 88, 'Maths': 81}
del marks['Biology']

Real output:

Traceback (most recent call last):
  File "demo.py", line 2, in 
    del marks['Biology']
        ~~~~~^^^^^^^^^^^
KeyError: 'Biology'

The same statement d[key] = value does two different jobs: if the key is new it adds the pair, if the key already exists it overwrites the value. Python decides by looking at whether the key is present. That is why a duplicate key in the literal {'a': 1, 'b': 2, 'a': 9} does not error — the second 'a' simply overwrites the first, and the dictionary ends up with two pairs.

del d[key] removes a pair, and it does raise KeyError for a missing key. Keys are unique; values need not be — two students can both score 91.

3. Which values can be a key?

A key must be immutable. Numbers, strings and tuples qualify. Lists do not.

seats = {('Delhi', 'Mumbai'): 4500, ('Delhi', 'Chennai'): 5200}
print(seats[('Delhi', 'Mumbai')])
print(seats['Delhi', 'Chennai'])

Real output:

4500
5200

Try to use a list as a key and Python refuses on the spot:

bad = {['Delhi', 'Mumbai']: 4500}

Real output:

Traceback (most recent call last):
  File "demo.py", line 1, in 
    bad = {['Delhi', 'Mumbai']: 4500}
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: unhashable type: 'list'

A tuple that contains a list is refused for exactly the same reason:

worse = {(1, [2, 3]): 'x'}

Real output:

Traceback (most recent call last):
  File "demo.py", line 1, in 
    worse = {(1, [2, 3]): 'x'}
            ^^^^^^^^^^^^^^^^^^
TypeError: unhashable type: 'list'

Why? A dictionary finds a value fast by computing a number from the key — its hash — and using that number to jump straight to the right slot. That only works if the key's hash never changes. A tuple is frozen, so its hash is fixed forever and it is a legal key. A list can be changed at any moment; if you used one as a key, appending to it later would change its hash and Python would lose the value it had filed away. So Python refuses up front with unhashable type: 'list'.

print(hash((2, 3)))
print(hash([2, 3]))

Real output:

8409376899596376432
Traceback (most recent call last):
  File "demo.py", line 2, in 
    print(hash([2, 3]))
          ~~~~^^^^^^^^
TypeError: unhashable type: 'list'

The exact number does not matter — what matters is that a tuple has one and a list does not, so the very first line of the program succeeds and the second one cannot. The {(1, [2, 3]): 'x'} example above shows the same rule applied all the way down: a tuple is hashable only when everything inside it is hashable too.

4. Membership tests keys, not values

d = {'Aarav': 87, 'Diya': 91, 'Kabir': 78}
print('Aarav' in d)
print(87 in d)
print('Rohit' not in d)
print(87 in d.values())

Real output:

True
False
True
True

87 in d is False because in looks only at keys. To search the values you must say in d.values().

5. Traversing a dictionary

marks = {'English': 78, 'Physics': 92, 'CS': 88}

for k in marks:
    print(k, marks[k])
print('---')
for k in marks.keys():
    print(k, end=' ')
print()
for v in marks.values():
    print(v, end=' ')
print()
for k, v in marks.items():
    print(k, '=', v)
print(marks.keys())
print(marks.values())
print(marks.items())
print(list(marks.keys()))
print(tuple(marks.items()))

Real output:

English 78
Physics 92
CS 88
---
English Physics CS 
78 92 88 
English = 78
Physics = 92
CS = 88
dict_keys(['English', 'Physics', 'CS'])
dict_values([78, 92, 88])
dict_items([('English', 78), ('Physics', 92), ('CS', 88)])
['English', 'Physics', 'CS']
(('English', 78), ('Physics', 92), ('CS', 88))

for k in marks: and for k in marks.keys(): do exactly the same thing — looping over a dictionary gives you its keys by default. items() is the neat one: each item is a (key, value) tuple, so you can unpack it straight into two loop variables. This is tuple unpacking from the earlier section doing real work.

Watch the printed form: keys() shows as dict_keys([...]), not as a plain list. In a written exam you must copy that wrapper exactly. If you actually need a list or tuple, convert with list() or tuple().

Dictionary literal d = {k1: v1, k2: v2} {} is an EMPTY DICTIONARY. Keys unique and immutable; values may repeat and be anything.
d[key] vs d.get(key) d[k] -> value or KeyError ; d.get(k, default) -> value or default get() never crashes. With no default it returns None.
Add / modify / delete d[k] = v ; del d[k] d[k]=v adds when k is new, overwrites when k exists. del on a missing key raises KeyError.
Membership k in d -> bool Checks KEYS only. For values use: v in d.values().
keys() / values() / items() d.keys(), d.values(), d.items() Return view objects printed as dict_keys([...]), dict_values([...]), dict_items([(k,v),...]). Wrap in list() or tuple() to convert.
Valid key types int, float, str, bool, tuple (NOT list, NOT dict) A list key raises TypeError: unhashable type: 'list'. So does a tuple that contains a list.
Remember
  • d[k] raises KeyError: 'k' for a missing key; d.get(k) returns None, and d.get(k, default) returns your default. This is the single most asked comparison in the chapter.
  • d[k] = v adds the pair if k is new and overwrites the value if k already exists — one statement, two jobs. Duplicate keys in a literal do not error; the last one wins.
  • Keys must be immutable. Tuples work as keys, lists give TypeError: unhashable type: 'list', because a list's hash could change after it is filed away.
  • x in d searches keys only; use x in d.values() to search values. len(d) counts pairs.
  • for k in d loops over keys; d.items() yields (key, value) tuples that unpack neatly into for k, v in d.items().

Dictionary Methods and the Two Syllabus Programs

Quick answer dict(), update(), pop(), popitem(), clear(), fromkeys(), setdefault() and copy() cover every dictionary operation the syllabus names, and get() turns character counting and salary records into three-line programs.

1. Building a dictionary with dict()

print(dict())
print(dict(Aarav=87, Diya=91))
print(dict([('Aarav', 87), ('Diya', 91)]))
print(dict((('CS', 88), ('IP', 79))))
print(dict(zip(('Jan', 'Feb', 'Mar'), (31, 28, 31))))

Real output:

{}
{'Aarav': 87, 'Diya': 91}
{'Aarav': 87, 'Diya': 91}
{'CS': 88, 'IP': 79}
{'Jan': 31, 'Feb': 28, 'Mar': 31}

A tuple of two-item tuples turns straight into a dictionary. The key=value form only works when the keys are valid Python names — you cannot write dict(Aarav Sharma=45000).

2. update()

marks = {'English': 78, 'Physics': 92}
marks.update({'CS': 88, 'English': 84})
print(marks)
marks.update(Maths=81)
print(marks)
marks.update([('Chem', 70)])
print(marks)
print(marks.update({'Bio': 60}))
print(marks)

Real output:

{'English': 84, 'Physics': 92, 'CS': 88}
{'English': 84, 'Physics': 92, 'CS': 88, 'Maths': 81}
{'English': 84, 'Physics': 92, 'CS': 88, 'Maths': 81, 'Chem': 70}
None
{'English': 84, 'Physics': 92, 'CS': 88, 'Maths': 81, 'Chem': 70, 'Bio': 60}

update() merges a second dictionary in: new keys are added, existing keys are overwritten (English became 84). The fourth line is the trap — print(marks.update(...)) prints None, because update() changes the dictionary in place and returns nothing. The change still happened, as the last line proves.

3. Removing things: pop(), popitem(), clear(), del

d = {'Aarav': 87, 'Diya': 91, 'Kabir': 78, 'Meera': 95}
print(d.pop('Kabir'))
print(d)
print(d.pop('Rohit', 'absent'))
print(d.popitem())
print(d)
print(d.clear())
print(d, len(d))

Real output:

78
{'Aarav': 87, 'Diya': 91, 'Meera': 95}
absent
('Meera', 95)
{'Aarav': 87, 'Diya': 91}
None
{} 0

That second argument is what rescued the pop('Rohit', 'absent') call. Without it, a missing key stops the program:

d = {'Aarav': 87, 'Diya': 91, 'Meera': 95}
print(d.pop('Rohit'))

Real output:

Traceback (most recent call last):
  File "demo.py", line 2, in 
    print(d.pop('Rohit'))
          ~~~~~^^^^^^^^^
KeyError: 'Rohit'

And popitem() on a dictionary that is already empty has nothing to remove:

d = {}
print(d.popitem())

Real output:

Traceback (most recent call last):
  File "demo.py", line 2, in 
    print(d.popitem())
          ~~~~~~~~~^^
KeyError: 'popitem(): dictionary is empty'

pop(key) removes the pair and returns the value, so you can use the deleted value. Give it a second argument and a missing key returns that instead of raising KeyError. popitem() takes no argument, removes the last inserted pair and returns it as a (key, value) tuple. clear() empties the dictionary and returns None — after it the dictionary still exists but has length 0, which is different from del d, which destroys the name itself.

OperationRemovesReturnsMissing key
del d[k]One pairNothing (a statement)KeyError
d.pop(k)One pairThe valueKeyError (unless default given)
d.popitem()Last pair(key, value) tupleKeyError on empty dict
d.clear()All pairsNoneNever fails

4. fromkeys() and setdefault()

print(dict.fromkeys(('CS', 'IP', 'Maths')))
print(dict.fromkeys(('CS', 'IP', 'Maths'), 0))
print(dict.fromkeys('UPI', 1))

marks = {'CS': 88}
print(marks.setdefault('CS', 0))
print(marks.setdefault('Maths', 0))
print(marks)
print(marks.setdefault('Bio'))
print(marks)

Real output:

{'CS': None, 'IP': None, 'Maths': None}
{'CS': 0, 'IP': 0, 'Maths': 0}
{'U': 1, 'P': 1, 'I': 1}
88
0
{'CS': 88, 'Maths': 0}
None
{'CS': 88, 'Maths': 0, 'Bio': None}

dict.fromkeys(seq, value) builds a dictionary from a sequence of keys, all sharing the same value — None if you do not supply one. Note that a string is a sequence of characters, so fromkeys('UPI', 1) makes three keys.

setdefault(k, v) is "get, but create it if it is missing". For 'CS' it returned the existing 88 and changed nothing. For 'Maths' the key did not exist, so it inserted 'Maths': 0 and returned 0. Compare that with get(), which returns a default but never inserts anything.

5. copy() versus plain assignment

a = {'CS': 88, 'IP': 79}
b = a.copy()
b['CS'] = 100
print(a)
print(b)

c = a          # NOT a copy, just another name
c['IP'] = 0
print(a)
print(c)
print(a is b, a is c)

Real output:

{'CS': 88, 'IP': 79}
{'CS': 100, 'IP': 79}
{'CS': 88, 'IP': 0}
{'CS': 88, 'IP': 0}
False True

b = a.copy() makes a real second dictionary, so editing b leaves a alone. c = a makes no copy at all — it just gives the same dictionary a second name, so editing through c shows up in a. a is c being True proves they are one object.

6. max(), min() and sorted() on a dictionary

salary = {'Aarav': 45000, 'Diya': 62000, 'Kabir': 38000}
print(max(salary))
print(min(salary))
print(sorted(salary))
print(sorted(salary, reverse=True))
print(max(salary.values()))
print(min(salary.values()))
print(sum(salary.values()))
print(sorted(salary.values()))
print(sorted(salary.items()))

Real output:

Kabir
Aarav
['Aarav', 'Diya', 'Kabir']
['Kabir', 'Diya', 'Aarav']
62000
38000
145000
[38000, 45000, 62000]
[('Aarav', 45000), ('Diya', 62000), ('Kabir', 38000)]

This catches people out every time: max(d) gives the largest key, not the largest value. 'Kabir' wins alphabetically even though he earns the least. To work with values you must say max(d.values()). sorted(d) likewise returns a sorted list of keys.

7. Syllabus program — count how many times each character appears in a string

First the long way, with an if:

s = "Chandrashekhar"
freq = {}
for ch in s:
    if ch in freq:
        freq[ch] = freq[ch] + 1
    else:
        freq[ch] = 1
print(freq)

Real output:

{'C': 1, 'h': 3, 'a': 3, 'n': 1, 'd': 1, 'r': 2, 's': 1, 'e': 1, 'k': 1}

Now the same thing using get(), which removes the if completely:

s = "Chandrashekhar"
freq = {}
for ch in s:
    freq[ch] = freq.get(ch, 0) + 1
print(freq)
print("Count of 'a' =", freq.get('a', 0))
print("Count of 'z' =", freq.get('z', 0))
print("Distinct characters =", len(freq))
for ch in sorted(freq):
    print(ch, '->', freq[ch])

Real output:

{'C': 1, 'h': 3, 'a': 3, 'n': 1, 'd': 1, 'r': 2, 's': 1, 'e': 1, 'k': 1}
Count of 'a' = 3
Count of 'z' = 0
Distinct characters = 9
C -> 1
a -> 3
d -> 1
e -> 1
h -> 3
k -> 1
n -> 1
r -> 2
s -> 1

freq.get(ch, 0) + 1 reads "whatever count this character already has, or 0 if it is new, plus one". Counting is the job dictionaries are best at, and this three-line loop is worth memorising. Note that 'C' and 'c' are different keys — sorting puts all capitals before all small letters. If the question says "ignore case", call s.lower() first.

8. Syllabus program — employees, their salaries, and accessing them

salary = {'Aarav Sharma': 45000, 'Diya Nair': 62000,
          'Kabir Singh': 38000, 'Meera Iyer': 71000}

print("Employee             Salary (Rs.)")
for name in salary:
    print(name.ljust(20), salary[name])

print("Employees      :", len(salary))
print("Total payout   :", sum(salary.values()))
print("Average salary :", sum(salary.values()) / len(salary))
print("Highest salary :", max(salary.values()))
print("Lowest salary  :", min(salary.values()))

# who earns the most - plain loop
top_name = ''
top_pay = 0
for name in salary:
    if salary[name] > top_pay:
        top_pay = salary[name]
        top_name = name
print("Top earner     :", top_name, "-", top_pay)

# safe access
print("Diya Nair      :", salary.get('Diya Nair'))
print("Rohit Verma    :", salary.get('Rohit Verma', 'Not on payroll'))

# 10% hike for Kabir, new joiner, one resignation
salary['Kabir Singh'] = salary['Kabir Singh'] + salary['Kabir Singh'] * 10 // 100
salary['Rhea Das'] = 52000
left = salary.pop('Aarav Sharma')
print("Aarav was on   :", left)
print(salary)

print("Above Rs.50000 :")
for name in sorted(salary):
    if salary[name] > 50000:
        print("  ", name, "->", salary[name])

Real output:

Employee             Salary (Rs.)
Aarav Sharma         45000
Diya Nair            62000
Kabir Singh          38000
Meera Iyer           71000
Employees      : 4
Total payout   : 216000
Average salary : 54000.0
Highest salary : 71000
Lowest salary  : 38000
Top earner     : Meera Iyer - 71000
Diya Nair      : 62000
Rohit Verma    : Not on payroll
Aarav was on   : 45000
{'Diya Nair': 62000, 'Kabir Singh': 41800, 'Meera Iyer': 71000, 'Rhea Das': 52000}
Above Rs.50000 :
   Diya Nair -> 62000
   Meera Iyer -> 71000
   Rhea Das -> 52000

Every dictionary operation in the syllabus appears here on real data: lookup by key, safe lookup with get(), modifying a value (Kabir's 10 per cent hike, 38000 becomes 41800), adding a new pair (Rhea joins), pop() to remove someone and keep their last salary, aggregate work with sum() and len() over values(), and sorted() for an alphabetical report. Notice again that the top earner had to be found with a loop, because max(salary) would have given the alphabetically last name.

dict() dict() / dict(k=v) / dict([(k, v), ...]) The key=v form needs valid identifiers, so dict(Aarav Sharma=1) is a syntax error.
update() d.update(other) -> None Adds new keys, overwrites existing ones. Returns None — never write d = d.update(x).
pop() / popitem() d.pop(k[, default]) -> value ; d.popitem() -> (key, value) pop without a default raises KeyError on a missing key. popitem removes the LAST inserted pair; on an empty dict it raises KeyError: 'popitem(): dictionary is empty'.
clear() and del d.clear() -> None ; del d[k] ; del d clear() leaves an empty dict of length 0; del d removes the name entirely.
fromkeys() / setdefault() dict.fromkeys(seq[, value]) -> dict ; d.setdefault(k[, v]) -> value fromkeys defaults every value to None. setdefault INSERTS the pair if k is missing; get() does not.
copy() vs assignment b = d.copy() (independent) vs c = d (same object) d is c -> True; d is b -> False. Editing c changes d; editing b does not.
max / min / sorted on a dict max(d), min(d), sorted(d) -> work on KEYS For values use max(d.values()), sum(d.values()). sorted(d.items()) gives a list of (k, v) tuples sorted by key.
Remember
  • update() and clear() return None — printing them prints None even though the dictionary really did change.
  • pop(k) returns the removed value; popitem() takes no argument, removes the last inserted pair and returns it as a (key, value) tuple.
  • setdefault(k, v) inserts the pair when k is missing and returns the value; get(k, v) returns a default but inserts nothing.
  • b = a.copy() makes an independent dictionary; c = a only makes a second name for the same one, so edits through c change a.
  • max(d), min(d) and sorted(d) work on KEYS. Use d.values() for values, and a plain loop to find which key holds the largest value.

The formula sheet

Every formula in this chapter, in one place — screenshot it before your exam.

t = (v1, v2, v3)
Tuple literaltuple
t = (5,)
Single-element tuple
t = () or t = tuple()
Empty tuple
tuple(iterable) -> tuple
tuple()
t[i] / t[-i]
Indexing
t[i] = x -> TypeError
Immutability
t1 + t2 -> tuple
Concatenation
t * n -> tuple
Repetition
x in t / x not in t -> bool
Membership
t[start:end:step] -> tuple
Slicing
a, b, c = t
Tuple assignment
x, y = y, x
Swap
len(t) -> int
len()
min(t), max(t), sum(t[, start])
min() / max() / sum()
sorted(t, reverse=False) -> list
sorted()
t.count(x) -> int
t.count()
t.index(x) -> int
t.index()
sum(t) / len(t) or statistics.mean(t)
Mean of a tuple
d = {k1: v1, k2: v2}
Dictionary literal
d[k] -> value or KeyError ; d.get(k, default) -> value or default
d[key] vs d.get(key)
d[k] = v ; del d[k]
Add / modify / delete
k in d -> bool
Membership
d.keys(), d.values(), d.items()
keys() / values() / items()
int, float, str, bool, tuple (NOT list, NOT dict)
Valid key types
dict() / dict(k=v) / dict([(k, v), ...])
dict()
d.update(other) -> None
update()
d.pop(k[, default]) -> value ; d.popitem() -> (key, value)
pop() / popitem()
d.clear() -> None ; del d[k] ; del d
clear() and del
dict.fromkeys(seq[, value]) -> dict ; d.setdefault(k[, v]) -> value
fromkeys() / setdefault()
b = d.copy() (independent) vs c = d (same object)
copy() vs assignment
max(d), min(d), sorted(d) -> work on KEYS
max / min / sorted on a dict

Test yourself

Tap an answer to check it instantly — you'll see why it's right, and what to revise if it isn't.

0 correct · 0/12 answered
Q1

What is the output?t = (1, 2, 3) print(t * 2 + t[1:])

Q2

What is the output?t = ("a", "b", "c", "d", "e") print(t[-4:-1])

Q3

Which statement about x = (7) is correct?

Q4

What is the output?d = {'a': 1, 'b': 2} d['c'] = d.get('a', 0) + d.get('z', 10) print(d)

Q5

What is the output?t = (10, 20, 30, 20, 10, 20) print(t.count(20), t.index(20), len(t))

Q6

What is the output?d = {1: 'one', 2: 'two', 3: 'three'} d.pop(2) d[4] = 'four' print(d.popitem())

Q7

What is the output?d2 = dict.fromkeys('CS', 0) print(d2)

Q8

What is the output?s = "level" f = {} for c in s: f[c] = f.get(c, 0) + 1 print(f, max(f.values()))

Q9

What is the output?d = {'p': 10, 'q': 20} e = d e['r'] = 30 f = d.copy() f['s'] = 40 print(len(d), len(e), len(f))

Q10

What is the output?t = (1, 2, [3, 4]) t[2].append(5) print(t)

Q11

marks = {'CS': 88, 'IP': 79, 'Maths': 95}What do max(marks) and max(marks.values()) print?

Q12

Which one of these is a valid dictionary key?

NCERT solutions & previous-year questions

Step-by-step model answers — tap a question to reveal the full solution.

NCERT questions 6

1 Consider the following tuples: tuple1 = (23, 1, 45, 67, 45, 9, 55, 45) and tuple2 = (100, 200). Find the output of: (i) print(tuple1.index(45)) (ii) print(tuple1.count(45)) (iii) print(tuple1 + tuple2) (iv) print(len(tuple2)) (v) print(max(tuple1)) (vi) print(min(tuple1)) (vii) print(sum(tuple2)) (viii) print(sorted(tuple1)) then print(tuple1)Tuple built-in functions and methods

All eight statements run together:

tuple1 = (23, 1, 45, 67, 45, 9, 55, 45)
tuple2 = (100, 200)
print(tuple1.index(45))
print(tuple1.count(45))
print(tuple1 + tuple2)
print(len(tuple2))
print(max(tuple1))
print(min(tuple1))
print(sum(tuple2))
print(sorted(tuple1))
print(tuple1)

Real output:

2
3
(23, 1, 45, 67, 45, 9, 55, 45, 100, 200)
2
67
1
300
[1, 9, 23, 45, 45, 45, 55, 67]
(23, 1, 45, 67, 45, 9, 55, 45)

Working:

  • (i) 45 sits at indexes 2, 4 and 7. index() reports only the first, so 2.
  • (ii) The same three occurrences give count() = 3.
  • (iii) Concatenation joins tuple2 to the end and returns a new 10-item tuple.
  • (iv) tuple2 has 2 items.
  • (v) and (vi) Largest is 67, smallest is 1.
  • (vii) 100 + 200 = 300.
  • (viii) sorted() returns a list in square brackets, and the final print(tuple1) proves the original tuple was not changed — this last line is the whole point of the question.
2 Consider the dictionary stateCapital = {"AndhraPradesh":"Hyderabad", "Bihar":"Patna", "Maharashtra":"Mumbai", "Rajasthan":"Jaipur"}. Find the output of: (i) print(stateCapital.get("Bihar")) (ii) print(stateCapital.keys()) (iii) print(stateCapital.values()) (iv) print(stateCapital.items()) (v) print(len(stateCapital)) (vi) print("Maharashtra" in stateCapital) (vii) print(stateCapital.get("Assam")) (viii) del stateCapital["Rajasthan"] then print(stateCapital)Dictionary access methods and traversal
stateCapital = {"AndhraPradesh": "Hyderabad", "Bihar": "Patna",
                "Maharashtra": "Mumbai", "Rajasthan": "Jaipur"}
print(stateCapital.get("Bihar"))
print(stateCapital.keys())
print(stateCapital.values())
print(stateCapital.items())
print(len(stateCapital))
print("Maharashtra" in stateCapital)
print(stateCapital.get("Assam"))
del stateCapital["Rajasthan"]
print(stateCapital)

Real output:

Patna
dict_keys(['AndhraPradesh', 'Bihar', 'Maharashtra', 'Rajasthan'])
dict_values(['Hyderabad', 'Patna', 'Mumbai', 'Jaipur'])
dict_items([('AndhraPradesh', 'Hyderabad'), ('Bihar', 'Patna'), ('Maharashtra', 'Mumbai'), ('Rajasthan', 'Jaipur')])
4
True
None
{'AndhraPradesh': 'Hyderabad', 'Bihar': 'Patna', 'Maharashtra': 'Mumbai'}

Working:

  • (ii), (iii), (iv) These do not print plain lists. You must copy the wrappers dict_keys([...]), dict_values([...]) and dict_items([...]) exactly, and note that each item of items() is a (key, value) tuple.
  • (v) len() counts pairs, so 4 — not 8.
  • (vi) in searches keys, and "Maharashtra" is a key, so True. Had the question asked "Mumbai" in stateCapital the answer would be False, because Mumbai is a value.
  • (vii) "Assam" is missing, so get() returns None. stateCapital["Assam"] would instead have stopped the program with KeyError: 'Assam'.
  • (viii) del removes the Rajasthan pair permanently; the remaining three keep their original order.
3 Write a program to read email IDs of n students and store them in a tuple. Create two new tuples, one storing only the usernames from the email IDs and the second storing the domain names. Print all three tuples at the end.Tuples, concatenation, string split()

An email ID has the form username@domain. The string method split('@') cuts it at the @ and returns a list of two pieces: piece 0 is the username, piece 1 is the domain. Since a tuple cannot be appended to, we grow each tuple with t = t + (item,) — and that trailing comma is compulsory.

n = int(input("How many email IDs? "))
emails = ()
for i in range(n):
    e = input("Enter email ID " + str(i + 1) + ": ")
    emails = emails + (e,)

users = ()
domains = ()
for e in emails:
    parts = e.split('@')
    users = users + (parts[0],)
    domains = domains + (parts[1],)

print("Emails   :", emails)
print("Usernames:", users)
print("Domains  :", domains)

Real run (what was typed appears after each prompt):

How many email IDs? 3
Enter email ID 1: aarav.sharma@priodemy.com
Enter email ID 2: diya99@gmail.com
Enter email ID 3: kabir_singh@nic.in
Emails   : ('aarav.sharma@priodemy.com', 'diya99@gmail.com', 'kabir_singh@nic.in')
Usernames: ('aarav.sharma', 'diya99', 'kabir_singh')
Domains  : ('priodemy.com', 'gmail.com', 'nic.in')

Points the examiner looks for: int() around the first input() because input always returns a string; emails = emails + (e,) rather than emails.append(e), which does not exist for tuples; and the fact that split() returns a list, so parts[0] and parts[1] are used to pick the two halves.

4 Write a program to input the names of n students and store them in a tuple. Then input a name from the user and find whether this student is present in the tuple or not.Tuples, linear search, membership

This is linear search on a tuple of strings. Set the position to -1 before the loop, scan from index 0, and break the moment a match is found.

n = int(input("How many students? "))
names = ()
for i in range(n):
    names = names + (input("Name " + str(i + 1) + ": "),)

print("Tuple of names:", names)
who = input("Name to search: ")

pos = -1
for i in range(len(names)):
    if names[i] == who:
        pos = i
        break

if pos == -1:
    print(who, "is NOT in the list")
else:
    print(who, "is present at index", pos)

Real run 1 — the name is present:

How many students? 4
Name 1: Aarav
Name 2: Diya
Name 3: Kabir
Name 4: Meera
Tuple of names: ('Aarav', 'Diya', 'Kabir', 'Meera')
Name to search: Kabir
Kabir is present at index 2

Real run 2 — the name is absent:

How many students? 4
Name 1: Aarav
Name 2: Diya
Name 3: Kabir
Name 4: Meera
Tuple of names: ('Aarav', 'Diya', 'Kabir', 'Meera')
Name to search: Rohit
Rohit is NOT in the list

Shorter alternative using the membership operator, which is accepted unless the question specifically asks for linear search:

if who in names:
    print(who, "is present at index", names.index(who))
else:
    print(who, "is NOT in the list")

Do not call names.index(who) without checking in first — for a missing name it raises ValueError: tuple.index(x): x not in tuple.

5 Write a Python program to find the highest two values in a dictionary.Dictionary values, sorted()

Pull out the values with d.values(), sort them from high to low with sorted(..., reverse=True), and read off the first two positions of the resulting list.

marks = {'Aarav': 87, 'Diya': 91, 'Kabir': 78, 'Meera': 95, 'Rhea': 91}

vals = sorted(marks.values(), reverse=True)
print("Values sorted high to low:", vals)
print("Highest two values      :", vals[0], vals[1])

# who scored them
for name in marks:
    if marks[name] == vals[0] or marks[name] == vals[1]:
        print(name, "->", marks[name])

Real output:

Values sorted high to low: [95, 91, 91, 87, 78]
Highest two values      : 95 91
Diya -> 91
Meera -> 95
Rhea -> 91

Working: the five values are 87, 91, 78, 95, 91. Sorted in reverse they are [95, 91, 91, 87, 78], so vals[0] is 95 and vals[1] is 91.

The tie is worth noticing. Diya and Rhea both scored 91, so three names are printed for two values. If the question wants two distinct values, drop the repeats first with dict.fromkeys(), which keeps each value once because dictionary keys are unique: sorted(dict.fromkeys(marks.values()), reverse=True) gives [95, 91, 87, 78], and the same top two. And remember max(marks) would have answered 'Rhea' — the alphabetically last key — not 95, which is why we work on marks.values() here.

6 Write a Python program to create a dictionary from a string, tracking the count of each letter. Sample string: 'w3resource'. Expected output: {'3': 1, 's': 1, 'r': 2, 'u': 1, 'w': 1, 'c': 1, 'e': 2, 'o': 1}Character frequency using a dictionary

Loop through the string one character at a time and use get(ch, 0) + 1: this reads the count the character already has, or 0 if it has never been seen, and adds one.

s = input("Enter a string: ")
d = {}
for ch in s:
    d[ch] = d.get(ch, 0) + 1
print(d)

Real run with the sample string:

Enter a string: w3resource
{'w': 1, '3': 1, 'r': 2, 'e': 2, 's': 1, 'o': 1, 'u': 1, 'c': 1}

Real run with another string:

Enter a string: Priodemy Academy
{'P': 1, 'r': 1, 'i': 1, 'o': 1, 'd': 2, 'e': 2, 'm': 2, 'y': 2, ' ': 1, 'A': 1, 'c': 1, 'a': 1}

About the "expected output" printed in the book: the counts match exactly — r appears twice, e appears twice, everything else once. Only the ORDER differs. The textbook shows the pairs in an older, unordered arrangement; from Python 3.7 onwards a dictionary keeps the order in which keys were first inserted, so 'w' comes first because it is the first character of the string. Both answers are correct; write the insertion order shown above.

The version without get() produces exactly the same dictionary and is equally acceptable:

for ch in s:
    if ch in d:
        d[ch] = d[ch] + 1
    else:
        d[ch] = 1

Note that the space character is counted too, and that 'A' and 'a' are separate keys. Use s.lower() first if the question says to ignore case, and add if ch != ' ': if spaces are to be skipped.

Previous-year board questions 4

Q1 Consider the tuple T = (10, 20, 30, 40, 50). Write the output of the following statements:(i) print(T[1:3])(ii) print(T[-2:])(iii) print(T * 2)(iv) print(len(T + T))(v) print(T.index(30) + T.count(10))(vi) print(sum(T) // len(T)) Board pattern — 3 marks
T = (10, 20, 30, 40, 50)
print(T[1:3])
print(T[-2:])
print(T * 2)
print(len(T + T))
print(T.index(30) + T.count(10))
print(sum(T) // len(T))

Real output:

(20, 30)
(40, 50)
(10, 20, 30, 40, 50, 10, 20, 30, 40, 50)
10
3
30

Working, statement by statement:

  • (i) Index 1 is 20, index 3 is excluded, so items at 1 and 2 give (20, 30).
  • (ii) -2 is 40 and no end means "to the finish", giving (40, 50).
  • (iii) Repetition writes the whole tuple out twice; it does not multiply the numbers. A very common wrong answer here is (20, 40, 60, 80, 100).
  • (iv) T + T has 10 items, so len is 10.
  • (v) 30 sits at index 2, and 10 occurs once, so 2 + 1 = 3.
  • (vi) sum(T) is 150 and len(T) is 5. Floor division gives 30 as an int; had the question used / the answer would be 30.0. Always write the decimal point when true division is used.

Remember: a printed tuple with one element must carry the comma, and an empty result must be written as ().

Q2 The following code is meant to print each employee's name and marks, but it produces an error. Identify the error, name it, correct the code, and rewrite it.D = {"Amit": 90, "Sneha": 76, "Ravi": 84} for K in D.keys(): print(K, D(K)) Board pattern — 2 marks

The actual error produced by running the code as given:

Traceback (most recent call last):
  File "demo.py", line 3, in 
    print(K, D(K))
             ~^^^
TypeError: 'dict' object is not callable

Error: D(K) uses round brackets. Round brackets after a name mean "call this like a function", and a dictionary is not a function. To look up a value you must use square brackets: D[K].

Name of the error: TypeError — and note it is a run-time error, not a syntax error. The line is perfectly valid Python grammar, which is why the program starts running and only then fails. Notice too that nothing at all was printed before the traceback: D(K) is worked out before print is called, so the very first turn of the loop fails.

Corrected code:

D = {"Amit": 90, "Sneha": 76, "Ravi": 84}
for K in D.keys():
    print(K, D[K])

Real output:

Amit 90
Sneha 76
Ravi 84

Two equally correct alternatives worth writing as a bonus line:

for K in D:              # .keys() is optional
    print(K, D[K])

for K, V in D.items():   # neatest
    print(K, V)
Q3 Differentiate between a list and a tuple with one example of each. Explain, with reason, why a tuple can be used as a dictionary key but a list cannot. Show the error a list key produces. Board pattern — 3 marks

Difference between a list and a tuple:

ListTuple
Written in square brackets [10, 20, 30]Written in round brackets (10, 20, 30)
Mutable — items can be changed, added or removedImmutable — nothing can be changed after creation
Has append(), remove(), sort(), insert() and moreHas only count() and index()
Cannot be a dictionary keyCan be a dictionary key

Why a tuple can be a key and a list cannot: a dictionary does not search through its keys one by one. It computes a number from each key, called the hash, and uses that number to jump straight to the slot where the value is stored. This trick only works if a key's hash can never change. A tuple is frozen the moment it is made, so its hash is fixed for life and it is safe to file a value under it. A list can be modified at any time — appending one item would change its hash, and Python would then look in the wrong slot and never find the value again. So Python blocks list keys at the point of creation instead of allowing a bug later.

The real error:

seats = {('Delhi', 'Mumbai'): 4500, ('Delhi', 'Chennai'): 5200}
print(seats[('Delhi', 'Mumbai')])
bad = {['Delhi', 'Mumbai']: 4500}

Real output:

4500
Traceback (most recent call last):
  File "demo.py", line 3, in 
    bad = {['Delhi', 'Mumbai']: 4500}
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: unhashable type: 'list'

The tuple keys worked and printed 4500; the list key stopped the program. A tuple that contains a list is rejected in the same way:

worse = {(1, [2, 3]): 'x'}

Real output:

Traceback (most recent call last):
  File "demo.py", line 1, in 
    worse = {(1, [2, 3]): 'x'}
            ^^^^^^^^^^^^^^^^^^
TypeError: unhashable type: 'list'

That second case is the extra mark: the rule is applied all the way down, so a tuple is hashable only if everything inside it is hashable too.

Q4 A kirana shop stores its cart as a dictionary where the key is the item name and the value is a tuple (unit price, quantity). Write a program to print an itemised bill, the subtotal, GST at 5 per cent, the amount payable, and the item whose line total is the highest. Board pattern — 5 marks

This question combines both halves of the chapter: a dictionary for the lookup, and a tuple as the value because a price-and-quantity pair has a fixed shape. Unpacking price, qty = info inside the loop keeps the code readable.

cart = {'Rice 5kg': (410, 2), 'Toor Dal 1kg': (185, 3), 'Mustard Oil 1L': (160, 1)}

total = 0
best_item = ''
best_amount = 0
print("Item              Price   Qty    Amount")
for item, info in cart.items():
    price, qty = info
    amount = price * qty
    total = total + amount
    if amount > best_amount:
        best_amount = amount
        best_item = item
    print(item.ljust(16), str(price).rjust(5), str(qty).rjust(5), str(amount).rjust(9))

gst = total * 5 / 100
print("Subtotal       :", total)
print("GST @5%        :", gst)
print("Payable        :", round(total + gst, 2))
print("Costliest line :", best_item, "-", best_amount)

Real output:

Item              Price   Qty    Amount
Rice 5kg           410     2       820
Toor Dal 1kg       185     3       555
Mustard Oil 1L     160     1       160
Subtotal       : 1535
GST @5%        : 76.75
Payable        : 1611.75
Costliest line : Rice 5kg - 820

Check the arithmetic: 410 x 2 = 820, 185 x 3 = 555, 160 x 1 = 160. Subtotal 820 + 555 + 160 = 1535. GST = 1535 x 5 / 100 = 76.75. Payable = 1611.75.

Marks are given for: using cart.items() so both key and value are available in one loop; unpacking the value tuple with price, qty = info (or equivalently info[0] and info[1]); a running total initialised to 0 before the loop; and finding the costliest line with a plain comparison loop. Do not attempt max(cart) here — that would compare the item NAMES and return 'Toor Dal 1kg', which is not what was asked.

Part of Priodemy for School

Interactive CBSE lessons, Class 8–12 — free with every school on Priodemy EduSuite. Explore more chapters and labs on the Priodemy for School hub.

Ask AI