A tuple is another of Python's sequence data types.
A tuple consists of a number of values separated by commas.
A tuple is a sequence of values of any type, indexed by integers. Similar to a list, but a tuple is immutable, thus it cannot be modified once created.
t = 1, 2, 3
print(t)
t = (1, 2, 3) # preferred syntax
print(t)
(1, 2, 3) (1, 2, 3)
If the tuple contains a single value only, then you must include the comma after the value.
t = 1,
print(t)
(1,)
This distinction is subtle so careful since you may wind up with something else.
t = ('a') # looks like a tuple, but alas it is not
print(type(t))
t = 1
print(type(t))
<class 'str'> <class 'int'>
To create an empty tuple, use ()
as a shortcut to tuple()
.
t = ()
print(t)
t = tuple()
print(t)
() ()
The tuple()
function is useful when you want to create a tuple from another sequence.
t = tuple('hello')
print(t)
('h', 'e', 'l', 'l', 'o')
print(t[0])
h
Use a slice to index one or more elements and return a tuple with the selected elements.
print(t[0:2])
('h', 'e')
Recall that tuples are immutable, so attempting to change an element will raise an error.
t[0] = 'H'
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) /var/folders/_5/pbybv9c90j77vqh9wby2v8140000gq/T/ipykernel_9636/3522562318.py in <module> ----> 1 t[0] = 'H' TypeError: 'tuple' object does not support item assignment
You can however reassign the variable a new tuple.
t = tuple('hello')
t = ('H',) + t[1:]
print(t)
t = tuple('Jello')
print(t)
('H', 'e', 'l', 'l', 'o') ('J', 'e', 'l', 'l', 'o')
One tuple is compared to another by comparing respective elements from each tuple until a decision can be made.
# 1 < 4 thus True
print((1, 2, 3) < (4, 5, 6))
# 1 > 0 thus False
print((1, 2, 3) < (0, 3, 4))
# 1 == 1, 2 < 3 thus True
print( (1, 2, 3) < (1, 3, 0))
True False True
Tuple assignment can be used in a lot of interesting ways, like swapping two values. Traditionally, this would require three variables.
# Traditional swap.
a = 1
b = 2
tmp = a
a = b
b = tmp
print(a, b)
2 1
a, b = (1, 2) # initialize a, b
a, b = (b, a) # swap a, b
print(a, b)
2 1
Notice the way a
and b
are initialized using a tuple, and also swapped using a tuple.
The right hand side expression can be any sequence as well.
Here the split()
method is used to return a list of elements that are assigned to the variables on the left hand side.
name, domain = 'monty@python.org'.split('@')
print(name, ':', domain)
monty : python.org
Using a tuple you can effectively return more than a single value from a function.
Let's look at an example of a function that returns the quotient and remainder.
def quotientRemainder(num, den):
return (num // den, num % den)
print(quotientRemainder(7, 3))
(2, 1)
Python actually offers just such a function, divmod()
.
print(divmod(7, 3))
(2, 1)
Here's a function that returns the min and max values of an iterable as a tuple.
def minMax(it):
return min(it), max(it)
print(minMax('Hello'))
print(minMax([1, 4, -9]))
print(minMax((1, 4, -9)))
# Capture returned values
minVal, maxVal = minMax([1, 4, -9])
print('min:', minVal, 'max:', maxVal)
('H', 'o') (-9, 4) (-9, 4) min: -9 max: 4
Functions often can accept a variable number of arguments. To define such a function use a *
in front of the parameter name, usually named args
by convention.
The *
basically gathers all the arguments into a tuple.
def printAll(*args):
# Print all the arguments.
print(args)
printAll(1, 2, 3)
printAll(1)
printAll(1, 'one', 1.0)
(1, 2, 3) (1,) (1, 'one', 1.0)
The reverse is also possible, i.e. you can scatter a tuple into its individual elements.
This is useful is you have a function that accepts a fixed number of parameters, and you want to use a tuple as the argument.
t = (7, 3) # a tuple
print(divmod(*t))
(2, 1)
Recall how min()
and max()
are able to accept a variable number of arguments. The sum()
function is an exception, since it accepts an iterable as its first argument instead.
print(sum(1, 2, 3))
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-19-f7d17cc49250> in <module> ----> 1 print(sum(1, 2, 3)) TypeError: sum() takes at most 2 arguments (3 given)
Let's define the sumAll()
function that can handle more than two arguments.
def sumAll(*args):
return sum(args)
print(sumAll(1, 2, 3))
6
zip()
is a built-in function that takes two or more sequences and returns an iterator of tuples. Each tuple contains corresponding elements from each list.
zip is in reference to a zipper and how it works, not some compression utility.
s = 'abc'
l = [1,2,3]
zip1 = zip(s, l)
zip2 = zip(l, l)
print(zip1, type(zip1))
print(zip2)
<zip object at 0x10bae4900> <class 'zip'> <zip object at 0x10bae4700>
Use a for
to iterate through the tuples themselves.
for t in zip1:
print(t, end=' ')
('a', 1) ('b', 2) ('c', 3)
If you want to get a list of tuples instead, use list()
.
lst = list(zip(s, l))
print(lst)
[('a', 1), ('b', 2), ('c', 3)]
If the sequences are of different lengths, the result has the same length as the shorter one.
for t in zip('ab', [1,2,3]):
print(t)
('a', 1) ('b', 2)
You can also use tuple assignment.
for letter, number in lst:
print(letter, number)
a 1 b 2 c 3
Combining zip()
, for
and tuple
assignment, you get a useful idiom for traversing two or more sequences at the same time.
The following example returns True
if two corresponding (same index) elements match. False
otherwise.
def hasMatches(seq1, seq2):
for left, right in zip(seq1, seq2):
if left == right:
return True
else:
return False
s = 'abc'
l = ['b', 'd', 'a']
print(hasMatches(s,l))
False
If you have a sequence and would like to traverse the elements and their indices, use the built-in function enumerate()
.
for index, value in enumerate('hello'):
print(index, value)
0 h 1 e 2 l 3 l 4 o
for index, t in enumerate(lst):
print(index, t)
0 ('a', 1) 1 ('b', 2) 2 ('c', 3)
Use the items()
method of a dictionary object to return an iterator of tuples, where each tuple is a key-value pair.
d = {'a': 1, 'b': 2, 'c': 3}
di = d.items()
print(di, type(di))
dict_items([('a', 1), ('b', 2), ('c', 3)]) <class 'dict_items'>
for key, value in di:
print(key, value)
a 1 b 2 c 3
You can go the other way as well. You can create a dictionary from a list of tuples.
l = [('a', 1),('b', 2),('c', 3)]
d = dict(l)
print(d)
{'a': 1, 'b': 2, 'c': 3}
Combining zip()
with dict()
gives us a nice way to create dictionary objects.
d = dict(zip('abc', range(1, 4)))
print(d)
{'a': 1, 'b': 2, 'c': 3}
Recall that a dictionary key must be hashable and thus immutable. A tuple meets both criteria and so can be used as a key.
Let's look at how we can use a tuple as a key to set up a telephone directory.
names = zip(['Doe', 'Doe'], ['John', 'Jane'])
phoneNumbers = ['555.1111', '555.1112']
contacts = dict(zip(names, phoneNumbers))
print(contacts)
{('Doe', 'John'): '555.1111', ('Doe', 'Jane'): '555.1112'}
print('John Doe:', contacts['Doe', 'John'])
John Doe: 555.1111
Create a separate Python source file (.py) in VSC to complete each exercise.
Download the file CROSSWD.TXT and rename it words.txt
. This file includes official crosswords and you will need it for the exercises.
Write a function called mostFrequent()
that takes a string and prints the letters in decreasing order of frequency.
Write a program that reads a word list from a file (words.txt
) and prints all the sets of words that are anagrams.
Here is an example of what the output might look like:
['deltas', 'desalt', 'lasted', 'salted', 'slated', 'staled']
['retainers', 'ternaries']
['generating', 'greatening']
['resmelts', 'smelters', 'termless']
Hint: you might want to build a dictionary that maps from a collection of letters to a list of words that can be spelled with those letters. The question is, how can you represent the collection of letters in a way that can be used as a key?
Modify the previous program so that it prints the longest list of anagrams first, followed by the second longest, and so on.
In Scrabble, a "bingo" is when you play all seven tiles in your rack, along with a letter on the board, to form an eight-letter word. What collection of eight letters forms the most possible bingos? Hint: there are seven.