The last data structure we will explore is the tuple. A tuple in mathematics is defined as a “finite ordered list” of items. So, it is a list of items that is not infinite, and the ordering of the items in that list matters.
Thankfully, Python includes support for immutable tuples directly in the language, so we can use them in our programs quickly and easily.
Tuples are generally used when:
- the number of entries in the container is fixed
- the values in the tuple will never change (tuples like strings are immutable)
- the programmer wants indexes which are continuous integers
- integer indexes may will not have gaps– if indexes 1,2 and 7 all have values then indexes 0, 3-6 exists but are assigned
- programmer cares what order Python stores the elements .. elements appear in a for-loop in index order
Creating a Tuple
To create a tuple in Python, we can simply assign multiple values to a variable, separated by commas:
tuple_one = 123, 456, 789
In Python, assigning values to a tuple in this way is referred to as packing. As with lists and dictionaries, we can even store different types of data in the same tuple, as seen below:
tuple_two = 876, "Hello", True
Tuples can be nested, using parentheses to enclose any inner tuples for clarity:
tuple_three = 123, ("Hello", True)
To create a tuple containing fewer than two elements, we must use some special syntax:
# empty tuple uses empty parentheses tuple_empty = () # single item tuple uses a comma after the item tuple_single = "Hello", # alterante t_single = ("Hello")
Using a Tuple
To access individual elements of a tuple, we can use the same square bracket notation
 we’ve learned with arrays:
tuple_access = 123, 456, "Hello" print(tuple_access) # 123 print(tuple_access) # 456 print(tuple_access) # Hello
We can also unpack values in a tuple, storing them in individual variables:
tuple_unpack = 123, 456, "Hello" x, y, message = tuple_unpack print(x) # 123 print(y) # 456 print(message) # "Hello"
We can even do the same for a method that returns a tuple:
x, y = get_coordinates();
As we can see, tuples appear to be very similar to lists in Python. However, tuples have one important property that sets them apart from lists—they are immutable. This means that once a tuple is created, the items it contains cannot be changed or updated:
tuple_modify = 123, 456, "Hello" tuple_modify = 789 # raises TypeError
So, we should always remember that items in a tuple cannot be modified, whereas a list can be modified. Because of that, we typically use tuples when returning data from a function or method, or when storing associated data in a list.
To really explore how we could use a tuple in our code, let’s build a simple program. Here’s a problem statement:
Write a program that will read lines of input from the terminal. Valid input is a single line with two space separated integers between 0-9.
The program should implement a simple search game. Players will guess coordinates on a 10x10 grid, trying to find a hidden item. So, input will take the form of two integers, separated by a space. If the program is unable to parse an input for any reason, it should print “Invalid Input!” and terminate the program.
When a player makes a guess, the program should respond with one of the four cardinal directions: “North”, “South”, “East”, “West”, indicating the direction of the hidden item from the guess. For simplicity, the program will only respond “North” or “South” if the player’s guess is not on the same row, or
xcoordinate, as the location, and “East” or “West” only if the player’s guess is on the same row as the location. If the player guesses correctly, simply print “Found!” and terminate the program. If the player repeats a guess, the program should print “Repeat!” instead of a cardinal direction.
The hidden location should be randomly generated and stored in a tuple as a global variable, and the program should maintain a global list of tuples representing the locations already guessed.
The program should be implemented as two functions:
main()that handles reading input and printing output, and a
make_guess()function that accepts two integers,
yas parameters, and responds with a string representing the result of that guess.
Let’s see if we can build this program using tuples.
First, let’s look at the main function. Once again, we’ll start with skeleton code that is very similar to the other examples in this chapter:
import sys import random class TupleExample: guesses =  location = None @staticmethod def main(args): reader = sys.stdin lines = "0 0" while len(lines.strip()) > 0: lines = reader.readline() if len(lines.strip()) > 0: try: val = lines.split(" ") x = int(val) y = int(val) output = TupleExample.make_guess(x, y) print(output) if output == "Found!": return except Exception as e: print("Invalid Input!") return def make_guess(x, y): # MORE CODE GOES HERE # main guard if __name__ == "__main__": TupleExample.main(sys.argv)
At the top of the class, we have included two fields to store our list of previous guesses and the location that should be guessed. For now, we’ll set that value to
None until we initialize it in our
In this code, we are simply reading a line of input, splitting it into two tokens, and then parsing each token to an integer to get the
y values of the guess. After that, we can call the
make_guess() function with those values, and print the result. Finally, we must check to see if the result is
"Found!". If so, we can terminate the program using the
Note: video unnecessarily marks the method `make guess` as a static method. We will follow the convention that only the start-up 'main' method shall be static.
Now that we have our
main() Method written, let’s work on the
make_guess() function. For starters, we must make sure our random location has been established. So, we’ll do that in the code shown below:
def make_guess(x, y): if TupleExample.location is None: TupleExample.location = random.randint(0, 9), random.randint(0, 9)
Here, we are using the
randint() method of the
random library to generate a number between
Now we must handle producing the output. First, we need to create a new tuple for the guess, and then check and see if the guess is correct, or if it has already been guessed:
def make_guess(x, y): if TupleExample.location is None: TupleExample.location = random.randint(0, 9), random.randint(0, 9) guess = x, y if guess == TupleExample.location: return "Found!" if guess in TupleExample.guesses: return "Repeat!"
Here, we are taking advantage of the fact that Python can automatically handle checking for equality between tuples as easily as any other value. As long as both tuples contain the same values in the same order, they are considered equal.
If we find out that the guess is not the hidden location, then we should store it in our list of guesses:
def make_guess(x, y): if TupleExample.location is None: TupleExample.location = random.randint(0, 9), random.randint(0, 9) guess = x, y if guess == TupleExample.location: return "Found!" if guess in TupleExample.guesses: return "Repeat!" TupleExample.guesses.append(guess)
Finally, we can handle printing the hints for cases where the guess is not on the same row:
def make_guess(x, y): if TupleExample.location is None: TupleExample.location = random.randint(0, 9), random.randint(0, 9) guess = x, y if guess == TupleExample.location: return "Found!" if guess in TupleExample.guesses: return "Repeat!" TupleExample.guesses.append(guess) if guess > TupleExample.location: return "North" if guess < TupleExample.location: return "South"
Below that, we can assume that the guess is on the same row, so we’ll have to handle the cases where the guess is east or west of the location:
def make_guess(x, y): if TupleExample.location is None: TupleExample.location = random.randint(0, 9), random.randint(0, 9) guess = x, y if guess == TupleExample.location: return "Found!" if guess in TupleExample.guesses: return "Repeat!" TupleExample.guesses.append(guess) if guess > TupleExample.location: return "North" if guess < TupleExample.location: return "South" if guess > TupleExample.location: return "West" else: return "East"
Tuples are useful, but limited. Conventional Python style is to use tuple when returning multiple values. However, using a tuple signals the grouping is only transitory. If a tuple represents a data aggregation that should be persistent, it is generally recommended that you make a class with properties and return an instance of t class instead. Classes can be better documented and extended.
def fie(): ... return a,b def fee(): ... t1= fee() foe(t1) z = t1.operation() ... def foe(x): ...
In this instance, it looks like the data returned by
fie is persistent, and maybe there should be a class for it. This is particularly true when a tuple contains lots of elements or it the tuple’s elements themselves are complex objects.
There we go! That method will handle producing the output for any guess provided by the user. See if you can complete the code in
TupleExample.py to the left, then use the two assessments below to check your program.
This content is presented in the course directly through Codio. Any references to interactive portions are only relevant for that interface. This content is included here as reference only.