Hands-on: Python Fundamentals -- Tuples

Objectives:

Upon completion of this lesson, you should be able to:

  • Describe the characteristics of the tuple in Python

  • Perform basic operations with tuples including creation, concatenation, repetition, slicing, and traversing

  • Get an idea in which situations tuples are and should be used

The tuple data structure

  • In Python, a tuple is an immutable sequence of values

  • Each value in the tuple is an element or item

  • Elements can be any Python data type

  • Tuples can mix data types

  • Elements can be nested tuples

  • Essentially tuples are immutable lists


Microquiz

So what does it mean to be immutable? Which immutable type(s) do you already know?


Creating tuples

  • You create tuples like you would lists, but with parentheses instead of brackets
In [ ]:
numbers = (1, 2, 3, 4)
print numbers
In [ ]:
cheeses = ('swiss', 'cheddar',
           'ricotta', 'gouda')

print cheeses
  • Note one difference, that tuples with only a single item without following "," reduce to that item
In [ ]:
t2 = ('a')
print t2, type(t1)

Microquiz

Can you give an explanation why it is so?


  • Also note that you can create tuples by omitting surrounding parantheses:
In [ ]:
t1 = 1, 
print t1
In [ ]:
t2 = 1, 2
print t2

and a trailing , would not have an additional effect:

In [ ]:
t2 = 1, 2,
print t2

Microquiz

Can you now exlain how magical

a, b = b, a

was "working"?


  • So to create a tuple with a single item, specify "," after the item:
In [ ]:
t2 = 'a',  # valid, but not recommended
print t2, type(t2)

t2 = ('a',) # more verbose, non-ambigous specification
print t2, type(t2)

t3 = tuple('a')
print t3, type(t3)

Nanoquiz

  1. What would be the result of

    (None,)
    

    ?

  2. Would

    tuple(1)
    

    work?


  • You can create an empty tuple simply with
In [ ]:
empty1 = ()
empty2 = tuple()

print empty1, empty2, empty1 is empty2, empty1 == empty2

which also shows that empty tuple is kinda unique.

In [ ]:
() is ()

Creating tuples from iterables

  • You can create tuples from any iterable by providing it to the tuple():
In [ ]:
alist = [1, 2, 3, 4]
tuple(alist)
In [ ]:
tuple(range(1, 5))
In [ ]:
astr = 'parrot'
tuple(astr)
In [ ]:
tuple("subj%d" % d for d in range(1, 4))

Note: Remember list comprehensions from the previous class? There is no dedicated tuple comprehension, but you could try running

("subj%d" % d for d in range(1, 4))

to get a glimpse into one of our future topics -- generators

Tuple indexing

  • Just like other sequences, elements within a tuple are indexed
In [ ]:
cheeses[0]
  • But the main difference of tuples from lists is that Tuples are immutable
In [ ]:
cheeses[0] = 'Feta'

Microquiz

What was another immutable sequence type in Python we have studied already?


Slicing a tuple

  • Like other sequences, tuples can be sliced
In [ ]:
cheeses[1:4]
  • Slicing a tuple creates a new tuple. It does not change the original tuple.

Using the + operator

  • You can use operators to manipulate tuples
  • The + operator returns a new tuple that is a concatenation of two tuples
In [ ]:
a = (1, 2, 3)
b = (4, 5, 6)
c = a + b

print a, b, c
  • Repeating with *
In [ ]:
a*3

Operations on tuples

  • Tuples support all the standard sequence operations, including:

    • Membership tests (using the in keyword)

    • Comparison (element-wise)

    • Iteration (e.g., in a for loop)

    • Concatenation and repetition

    • The len() function

Comparisons

Docs (https://docs.python.org/2/library/stdtypes.html#sequence-types-str-unicode-list-tuple-bytearray-buffer-xrange) say:

Sequence types also support comparisons. In particular, tuples and lists are compared lexicographically by comparing corresponding elements. This means that to compare equal, every element must compare equal and the two sequences must be of the same type and have the same length.

Also this:

Tuples and lists are compared lexicographically using comparison of corresponding elements. This means that to compare equal, each element must compare equal and the two sequences must be of the same type and have the same length.
In [ ]:
(3, 4) < (3, 5)
In [ ]:
(3, 4) < (2, 5)

Tuples and functions

  • Remember that a function can only return one value

  • That is why many Python functions return tuples to "pack" multiple return values into it

Consider for example this simple min_max function:

In [ ]:
def min_max(t):
    """Returns the smallest and largest elements of a sequence as a tuple"""
    return min(t), max(t)

seq = [12, 98, 23, 74, 3, 54]
print min_max(seq)

which we can "unpack" into variables right away:

In [ ]:
min_v, max_v = min_max(seq)
print min_v, max_v

Excercises

  1. What other sequences above min_max would be applicable to? Try with other types

  2. What will happen if you try to unpack to smaller or larger number of variables?


Positional arguments to the function are passed as a tuple

  • A parameter name that begins with * gathers all the arguments into a tuple

  • This allows functions to take a variable number of arguments

In [ ]:
def print_all(*args):
    print args

print_all(1, 2.0, 'three')

and here is a bit more elaborate case, when *args are complimenting the main set of argument(s):

In [ ]:
def formatted_msg(msg, *args):
    if args[0] < 10000000 and "Hawai" in str(args[1:]):
        print "Stop dreaming"
    else:
        print msg % args

formatted_msg("If I had a %d bucks, I would have got %s, %s and %s", 1000000, "moved to Hawai", "bought kids a yaht", "sent them away")

Nanoexcercise

"Make it happen" in the above code example ;)

Using tuple assignment in a for loop

  • Tuples can be very handy when looping
  • You can assign each value of a tuple to a separate variable
In [ ]:
t = [('a', 0), ('b', 1), ('c', 2)]
for letter, number in t:
    print number, letter
  • Remember zip function? It is usually used to provide synchronized traversing of multiple iterables (lists, strings, ..), and used in conjunction with "tuple packing":
In [ ]:
def has_match(t1, t2):
    for x, y in zip(t1, t2):
        if x == y:
            return True
    return False

a = [5, 4, 9, 7, 10]
b = [4, 3, 5, 7, 15]
print has_match(a, b)
print has_match("abcabc",
                "cbacba")

Tuples vs Lists -- when to use which?

http://stackoverflow.com/a/16941245

Raymond Hettinger (one of the Python core developers) had this to say about tuples in a recent tweet:

#python tip:Generally, lists are for looping; tuples for structs. Lists are homogeneous; tuples heterogeneous. Lists for variable length.

+ tuples can serve as "keys" for dictionaries (next lecture), lists -- can't

Extra for hungry minds: namedtuple

Because tuples---as recommended above by Raymond himself---are often used for storing heterogeneous records, namedtuple was introduced to provide tuples where entries could have names. You can get a glimpse by simply running

from collections import namedtuple
namedtuple?

in IPython shell or checking out https://docs.python.org/2/library/collections.html#collections.namedtuple