Tuples are immutable

  • A tuple is a sequence of values
  • They values can be any type and are index by integers
  • They are similar to lists, except:
    • Tuples are immutable
    • Tuples values usually have different types (unlike lists which generally hold only a single type)
  • There are multiple ways to create a tuple

In [1]:
a_tuple = ( 'a', 'b', 'c', 'd', 'e' )
a_tuple = 'a', 'b', 'c', 'd', 'e'
a_tuple = 'a',

type( a_tuple )


Out[1]:
tuple
  • If you want to create a tuple with a single value, add a comma (,) after the value, but don’t add parenthesis
  • You can also use the built in function tuple

In [2]:
a_tuple = tuple()
print( a_tuple )
a_tuple = tuple( 'lupins' )
print( a_tuple )


()
('l', 'u', 'p', 'i', 'n', 's')
  • Most list operators (e.g., bracket and slice) work on tuples
  • If you try to modify one of the elements, you get an error

In [3]:
a_tuple = ( 'a', 'b', 'c', 'd', 'e' )
print( a_tuple[1:3] )
print( a_tuple[:3] )
print( a_tuple[1:] )

# Uncomment to see error
# a_tuple[0] = 'z'


('b', 'c')
('a', 'b', 'c')
('b', 'c', 'd', 'e')

Tuple assignment

  • Often, you may want to swap the values of two variables
  • This is done conventionally using a temporary variable for storage

In [4]:
a = 5
b = 6

# Conventional value swap
temp = a
a = b
b = temp

print( a, b )


6 5
  • Python allows you to do it using a tuple assignment

In [5]:
a, b = b, a
print( a, b )


5 6
  • On the left is a tuple of varaibles and on the right is a tuple of expressions
  • Note that the number on each side of the equality sign must be the same
  • The right side can be any kind of sequence (e.g., a string or list)

In [6]:
addr = 'monty@python.org'
uname, domain = addr.split( '@' )
print( uname )
print( domain )


monty
python.org

Tuples as return values

  • A function can only return one value
  • However, if we make that value a tuple, we can effectively return multiple values
  • For example, the divmod function takes two (2) arguments and retunrs a tuple of two (2) values, the quotient and remainder

In [7]:
quotient, remainder = divmod( 7, 3 )
print( quotient )
print( remainder )


2
1
  • Note the use of a tuple assignment
  • Here is how to build a function that returns a tuple

In [8]:
def min_max( a_tuple ):
    return min( a_tuple ), max( a_tuple )

numbers = ( 13, 7, 55, 42 )
min_num, max_num = min_max( numbers )
print( min_num )
print( max_num )


7
55
  • Note that min and max are built-in functions

Variable-length argument tuples

  • All the functions we have built and used required a specific number of arguments
  • You can use tuples to build functions that accept a variable number of arguments
  • Prepend the argument’s variable name with an * to do this
  • It is referred to as the gather operator

In [9]:
def printall( *args ):
    print( args )

printall( 1 , 2.0 , '3' )


(1, 2.0, '3')
  • The complement is the scatter operator
  • It allows you to pass a sequence of values as individual arguments to the function

In [10]:
a_tuple = ( 7, 3 )
# divmod( a_tuple ) # Uncomment to see error
divmod( *a_tuple )


Out[10]:
(2, 1)

Lists and tuples

  • The zip function takes two or more sequences and "zips" them into a list of tuples

In [11]:
a_string = 'abc'
a_list = [ 0, 1, 2 ]
for element in zip( a_string, a_list ):
    print( element )


('a', 0)
('b', 1)
('c', 2)
  • Essentially, it returns an iterator over a list of tuples
  • If the sequences aren't the same length, the result has the length of the shorter one

In [12]:
for element in zip( 'Peter', 'Tony' ):
    print( element )


('P', 'T')
('e', 'o')
('t', 'n')
('e', 'y')
  • You can also use tuple assignment to get the individual values

In [13]:
a_list = [ ('a', 0), ('b', 1), ('c', 2) ]
for letter, number in a_list:
    print( letter, number )


a 0
b 1
c 2
  • You can combine zip, for and tuple assignment to traverse two (or more) sequences at the same time

In [14]:
def has_match( tuple1, tuple2 ):
    result = False
    for x, y in zip( tuple1, tuple2 ):
        if( x == y ):
            result = True
    return result
  • If you need the indices, use the enumerate function

In [15]:
for index , element in enumerate( 'abc' ):
    print( index, element )


0 a
1 b
2 c

Dictionaries and tuples

  • The method items returns a tuple of key-value pairs from a dictionary

In [16]:
a_dict = { 'a': 0, 'b':1, 'c':2 }
dict_items = a_dict.items()

print( type( dict_items ) )
print( dict_items )

for element in dict_items:
    print( element )


<class 'dict_items'>
dict_items([('a', 0), ('b', 1), ('c', 2)])
('a', 0)
('b', 1)
('c', 2)
  • Remember that there is no particular ordering in a dictionary
  • You can also add a list of tuples to a dictionary using the update method
  • Using items, tuple assignment, and a for loop is an easy way to traverse the keys and values of a dictionary

In [17]:
for key, value in a_dict.items():
    print( key, value )


a 0
b 1
c 2
  • Since tuples are immutable, you can even use them as keys in a dictionary

In [18]:
directory = dict()
directory[ 'Smith', 'Bob' ] = '555-1234'
directory[ 'Doe', 'Jane' ] = '555-9786'

for last, first in directory:
    print( first, last, directory[last, first] )


Bob Smith 555-1234
Jane Doe 555-9786
  • Examples of a state diagram for a tuple can be found on pg. 121

Comparing tuples

  • Relational operators work with tuples as well
  • The process is:
    1. Compare the first item
    2. If they are equal, go on to the next one
    3. Continue until elements that differ are found
    4. Subsequent elements are ignored

Sequences of sequences

  • In many situations, the different kinds of sequences (i.e., strings, lists, and tuples) can be used interchangeably
  • When do you choose one over the other?
  • Strings are more limited since they are immutable and the elements have to be characters
  • Lists are more common than tuples (mainly because they are mutable)
  • Prefer tuples when:
    • It is syntactically easier to create a tuple (like a return statement)
    • You want to use a sequence as a dictionary key. If so, you need to use a string or a tuple since they are immutable
    • If you passing a sequence as an argument to a function, using tuples reduces the potential for unexpected behavior due to aliasing
  • Since tuples aren’t immutable, you can’t sort or reverse them
  • However, there are the functions sorted and reversed which return a new sequence with the ordering changed

Debugging

  • Lists, dictionaries and tuples are known generically as data structures
  • We dive into these data structures more in other courses

Exercises

  • Many of the built-in functions use variable-length argument tuples. For example, max and min can take any number of arguments, but sum does not. Write a function called sum_all that takes any number of arguments and returns their sum.
  • Write a function called print_all that takes a variable number of arguments and prints each one on its own line.
  • Write a function called distance that takes two (2) two-dimensional points and returns the distance between them. Then, extend your function to use three-dimensional points. Can you generalize it to take two points of any dimension?
  • Write a function called merge that takes two (2) sorted tuples and returns a new tuple that contains all the elements in the two tuples in sorted order. Write both a recursive and an iterative solution.