# tuples.py # Remember that a string is an ordered sequence of characters? # Also remember that a list is an ordered sequence of values of any type? # We said both strings and lists and other things that behave like ordered # sequences are called sequences. # Also remember that strings are immutable and lists are mutable? # # A tuple, like a list, is a sequence of items of any type. Unlike lists, # however, tuples are immutable. The values of a tuple are indexed by # integers as the values in a list or string. # As you will see below, sequences (strings, lists, and tuples) share # some common operators. # Since a tuple is a data structure, think about four things that I talked # about when I introduced strings to you: # # (1) How do you create one? # (2) How do you access an element in it? # (3) How do you modify an element in it in place if possible? # Note that tuples are immutable! # (4) How do you destroy it when we don't need it any more? (don't worry # about it) # Let us see some tuples and related functions that we can use to manipulate # tuples. Also think about where tuples would be useful in programming. # Syntactically, a tuple is a comma-separated sequence of values. # a = 2, 3, 4, 6, 7, 10 print a # (2, 3, 4, 6, 7, 10) # Although it is not necessary, it is conventional to enclose tuples in # parentheses: # b = (20, 30, 40, 60, 70, 100) print b # (20, 30, 40, 60, 70, 100) # To create a tuple with a single element, we have to include the final comma. # Without the comma, Python treats (5) as an integer in parentheses. # tup = (22,) print type(tup) # # Another way to create a tuple is the built-in function tuple. # With no argument, it creates an empty tuple: # t = tuple() print t # () # If the argument is a sequence (string, list, or tuple), the result is a # tuple with the elements of the sequence: # t = tuple('apple') print t # ('a', 'p', 'p', 'l', 'e') # Most list operators work on tuples. The bracket operator indexes an element: # tup = ('a', 'b', 'c', 'd', 'e') print tup[0] # 'a' # And the slice operator selects a range of elements: # print tup[1:3] # ('b', 'c') # As expected you can't modify an element in place - immutable! # # tup[2] = 'K' # this would produce an error. What kind of error? Try it! # Although we can't replace an element in place, we can rebind the variable # with a new tuple: # tup = ('a', 'b', 'K', 'd', 'e') #-------------------------------- # Tuple assignments # # It is often useful to swap the values of two variables. # Tuple assignment is convenient. To swap the values of a and b we can do # the following: print a print b a, b = b, a print a print b # The left side is a tuple of variables; the right side is a tuple of # expressions. Each value is assigned to its respective variable. # All the expressions on the right side are evaluated before any of the # assignments. The number of variables on the left and the number of # values on the right have to be the same. # More generally, the right side can be any kind of sequence (string, list, # or tuple). For example, to split an email address into a user name and # a domain, you could write: # addr = 'monty@python.org' uname, domain = addr.split('@') #-------------------------------- # Tuples as return values # # Functions can return tuples as return values. For example, we could write # a function that swap two parameters like this: # def swap(x, y): return y, x # Then do the following to swap: a, b = swap(a, b) # What would this definition of swap (called swapbad) do? # def swapbad(x, y): x, y = y, x # If we call this function like this: swapbad(a, b) # then changing x inside swapbad makes x refer to a different value, # but it has no effect on a in the __main__ frame. Similarly, changing y # has no effect on b. # This would do the right thing, but a function like this would be # redundant. I am using this example to illustrate local variables # and their relationship with variables outside a function, i.e., global # variables. def swapgood(x, y): x, y = y, x return x, y a, b = swapgood(a, b) #-------------------------------- # Lists and tuples # # zip is a built-in function that takes two or more sequences and "zips" # them into a list of tuples where each tuple contains one element from # each sequence. # # This example zips a string and a list: s = 'abc' t = [0, 1, 2] zip(s,t) # [('a', 0), ('b', 1), ('c', 2)] # You can use tuple assignment in a for loop to traverse a list of tuples: t = [('a', 0), ('b', 1), ('c', 2)] for letter, number in t: print number, letter # Each time through the loop, Python selects the next tuple in the list and # assigns the elements to letter and number. The output of this loop is: # # 0 a # 1 b # 2 c # If you combine zip, for, and tuple assignment, you get a useful idiom for # traversing two (or more) sequences at the same time. For example, has_match # takes two sequences, t1 and t2, and returns True if there is an index i such # that t1[i] == t2[i]: def has_match(t1, t2): for x, y in zip(t1, t2): if x == y: return True return False # If you need to traverse the elements of a sequence and their indices, you can # use the built-in function enumerate: for index, element in enumerate('abc'): print index, element # The output of this loop is again: # # 0 a # 1 b # 2 c # I will stop on tuples here. If you want to learn more on tuples, read # Chapter 12 of [Downey]