Doubles, Triples, Quadruples : The tuple

Tuple is a generalization from words like double, triple, quadruple, quintuple. The common ending to all these words appears to be “tuple”. The computer-science folks extracted the suffix and made a new word (I think they call these back-formations or neologisms), tuple, out of the suffix.

A tuple is an immutable sequence of items.

We’ll look at some common patterns of tuple processing in Translating From Math To Python: Conjugating The Verb “To Sigma”.

What Does “Tuple” Mean?

A tuple is an immutable sequence of Python objects.

Mathematicians commonly work with ordered pairs. For instance, most analytical geometry is done with Cartesian coordinates (x, y), an ordered pair, or 2-tuple. All vector math can be done with tuples. These are remarkably common in mathematics, and we can create a neat, easy-to-read implementation in Python.

Here are some of the properties of tuples in Python.

  • Since a tuple is a sequence, all of the common operations and built-in functions of sequences apply. This includes +, * and []. See Basic Sequential Collections of Data for more information on the these operations.
  • Since a tuple is immutable, it cannot be changed. This parallels the way a number, like 5, is immutable.
  • While tuples are an extension to the basic sequence type, they don’t have any additional method functions; they are the “basic” sequence.

An essential ingredient here is that a tuple has a fixed and known number of items. For example a 2-dimensional geometric point might have a tuple with x and y. A 3-dimensional point might be a tuple with x, y, and z. The size of the tuple does not change. Indeed, the size of the tuple is a matter of what the program was designed to do.

Here’s a depiction of a tuple of 3 items, the Python value is the RGB color code for a nice midnight-blue: (51, 0, 153). Each item has a position that identifies the item in the tuple.

position 0 1 2
item 51 0 153

Immutability of Tuples. When someone asks about changing a tuple, we have to remind them that the list, in Flexible Sequences : The list, is for dynamic sequences of items. A tuple is generally used when the number of items is fixed by the nature of the problem. For example, 2-dimensional geometry, or a 4-part internet address, or a Cyan-Mangenta-Yellow-Black color code. Using a tuple, with a fixed number of items, saves Python from all of the bookkeeping necessary when there is a dynamic number of items.

Another common use for tuples is to create a function that returns multiple values. When we put multiple values in a return statement, we are creating a tuple. An example would be a function that simulates rolling two dice and returns a tuple with two dice values.

How We Write Tuples

Tuples are created by surrounding the sequence of objects with () and separating the objects with commas (,). This matches the conventional mathematical notation for coordinates: (2,3) is two-dimensional, (1,5,8) is a three-dimensional point.

Tuple items do not have to be the same type. A tuple can be a mixture of any Python data types, including lists, tuples, strings and numeric types.

Examples:

xy= (2, 3)
personal= ('Hannah',14,5*12+6)
singleton= ("hello",)
zero_tuple = ()
p2= ( "Hannah", (3,8,85), u'G\xe4llivare', )
xy:A typical 2-tuple.
personal:A 3-tuple with name and two numbers.
singleton:A 1-tuple. The , is mandatory. Without the ,, this is just an expression in ().
zero_tuple:A way to specify a tuple with no actual data in it.
p2:A 3-tuple with a string, another 3-tuple ((3,8,85)) and a Unicode string. The extra , at the end is quietly ignored.

Important

But Wait!

“But wait!” you say. The () characters are used to identify parts of an expression. And the identify the argument values to a function. How can they also be used to define a new tuple object?

In the case of (), the context helps Python determine how to interpret these characters.

  • When you have something like a(b), this is a function application.
  • When you have (b) by itself, this is an expression.
  • When there is at least one , (as in (a,b) or (a,)), this is a tuple.
  • If we say just (), this is a tuple with zero items. It’s a strange degenerate case, but might be useful as a placeholder in a complex data object.

A pleasant consequence of this is that an extra comma at the end of a tuple is legal; for example, (9, 10, 56, ) is still a three-tuple.

The Tuple Factory Function

In addition to literal values, the following function also creates a tuple object out of another sequence.

tuple(sequence) → tuple

Creates a tuple from the items in sequence. If the sequence is omitted, an empty tuple is created.

>>> tuple()
()
>>> tuple( "hi mom" )
('h', 'i', ' ', 'm', 'o', 'm')

In the second example, a string, which is a kind of sequence, is transformed into a tuple of individual characters.

Operations on Tuples

There are three standard sequence operations (+, *, []) that can be performed with tuples as well as lists and strings.

The + operator. The + operator creates a new tuple as the concatenation of the arguments. Here’s an example.

>>> ("part",8) + ("strings","tuples","lists")
('part', 8, 'strings', 'tuples', 'lists')

The * operator. The * operator between tuples and numbers (number * tuple or tuple * number) creates a new tuple that is a number of repetitions of the input tuple.

>>> 2*(3,"blind","mice")
(3, 'blind', 'mice', 3, 'blind', 'mice')

The [] operator. The [] operator selects an item or a slice from the tuple. There are two forms for picking items or slices from a tuple.

This form extracts a single item.

tuple[index]

Items are numbered from 0 to len(tuple)-1. Items are also numbered in reverse from -len(tuple) to -1.

This extracts a slice, creating a new sequence from a sequence.

tuple[start:end]

Items from start to end-1 are chosen to create a new tuple as a slice of the original tuple; there will be end - start items in the resulting tuple. If start is omitted it is the beginning of the tuple (position 0), if end is omitted it is the end of the tuple (position -1).

For more information on how the numbering works for the [] operator, see Numbering from Zero.

Here are some examples of selecting items or slices from a larger 5-tuple.

>>> t=( (2,3), (2,"hi"), (3,"mom"), 2+3j, 6.02E23 )
>>> t[2]
(3, 'mom')
>>> print( t[:3], 'and', t[3:] )
((2, 3), (2, 'hi'), (3, 'mom')) and ((2+3j), 6.02e+23)
>>> print(t[-1], 'then', t[-3:])
6.02e+23 then ((3, 'mom'), (2+3j), 6.02e+23)

The % Operator. The string format operator works between string and tuple. We prefer to use str.format(), however.

Built-in Functions for Tuples

A number of built-in functions create or process tuples.

len(iterable) → integer

Return the number of items of a set, sequence or mapping.

>>> some_tuple = ("part",8) + ("strings","tuples","lists")
>>> len( some_tuple )
5
max(iterable) → value

Returns the largest value in the iterable (sequence, set or mapping).

>>> stats = ( (5,'zero'), (43,'red'), (52, 'black') )
>>> max( stats )
(52, 'black')
min(sequence) → value

Returns the smallest value in the iterable (sequence, set or mapping).

>>> stats = ( (5,'zero'), (43,'red'), (52, 'black') )
>>> min( stats )
(5, 'zero')

Some other functions which apply to sequences in general are available. However, they don’t much much sense for tuples. The iteration functions, like enumerate(), sorted(), reversed() and zip() are valid, but aren’t very meaningful.

Aggregation Functions. The following functions create an aggregate value from a tuple.

sum(iterable) → number

Sum the values in the iterable (set, sequence, mapping). All of the values must be numeric.

>>> sum( ( 1, 3, 5, 7, 9 ) )
25
all(iterable) → boolean

Return True if all values in the iterable (set, sequence, mapping) are equivalent to True.

>>> compare_1 = ( 2<=3, 5<7, 22%2 == 0 )
>>> all( compare_1 )
True
>>> compare_2 =  ( 2 > 3, 5<7, 22%2 == 0 )
>>> all( compare_2 )
False
>>> compare_2
(False, True, True)
any(iterable) → boolean

Return True if any value in the iterable (set, sequence, mapping) is equivalent to True.

>>> roll = 7
>>> any( (roll == 7, roll == 11) )
True
>>> any( (roll == 2, roll == 3, roll == 12) )
False

Making Comparisons Between Tuples

The standard comparisons (<, <=, >, >=, ==, !=, in and not in) work the same with tuples as they do with strings. The tuples are compared item by item. If the corresponding items are the same type, ordinary comparison rules are used. If the corresponding items are different types, the type names are compared, since there is almost no other rational basis for comparison.

>>> a=(1,2,3,4,5)
>>> b=(9,8,7,6,5)
>>> if a < b: print("a smaller")
... else: print("b smaller")
...
a smaller
>>> 3 in a
True
>>> 3 in b
False

Here’s a longer example

from __future__ import print_function
import random
n= random.randrange(38)
if n == 0:
    print('0', 'green')
elif n == 37:
    print('00', 'green')
elif n in ( 1,3,5,7,9, 12,14,16,18, 19,21,23,25,27, 30,32,34,36 ):
    print(n, 'red')
else:
    print(n, 'black')

This will create a random number, setting aside the zero and double zero. If the number is in the tuple of red spaces on the Roulette layout, this is printed. If none of the other rules are true, the number is in one of the black spaces.

Statements and Tuples

There are two kinds of statements that are associated with tuples: the various kinds of assignment statements and the for statement deals with sequences of all kinds.

The Assignment Statements. There is a variation on the assignment statement called a multiple-assignment statement that works nicely with tuples. We looked at this in Combining Assignment Statements. We quietly slipped past the tuple-ness of the multiple assignment statement. Multiple variables can set by decomposing the items of a tuple.

>>> x,y=(1,2)
>>> x
1
>>> y
2

An essential ingredient here is that a tuple has a fixed and known number of items. For example a 2-dimensional geometric point might have a tuple with x and y. A four-part color code might be a tuple with c, m, y and b.

This works well because the right side of the assignment statement is fully evaluated before the assignments are performed. This allows things like swapping two variables with x,y=y,x.

The for Statement. The for statement also works directly with sequences like tuples. The range() function that we have used creates a kind of sequence called a list. A tuple is also a kind of sequence and can be used in a for statement.

s= 0
for i in ( 1,3,5,7,9, 12,14,16,18, 19,21,23,25,27, 30,32,34,36 ):
    s += i
print("total", s)

Translating From Math To Python: Conjugating The Verb “To Sigma”

If you already know about the sigma operator, \Sigma, you can skip this section. This is background for the basic statistical formulas that we’ll implement on tuples of data values.

The sigma operator, \Sigma, is used in a number of common statistical algorithms. While there are a lot of flashy mathematical symbols here, the purpose of this section is to demystify the math. This information can help give you the necessary background to tackle the exercises.

We can think of \Sigma as a complicated verb with a few prepositional phrases. The basic meaning of \Sigma is “to sum”. The reason why we use the Greek version of “S” for “sum” is because we’re not talking generally about “summing”. We have to provide three pieces of information as part of a summation:

  • The function we’re summing. Picking a specific value out of a tuple with the [] operator will be the function we’re summing.
  • A variable which occurs in the function. We’ll call this the “bound” variable because it is bound to this sigma operation.
  • A range of values for the bound variable.

Here’s the basic summation operation, showing the typical form for the \Sigma operator.

\sum_{i=0}^{n} f(i)

The \Sigma operator has the three additional clauses written around it.

  • Below are the bound variable, i, and the starting value for the range, written as i=0.
  • Above is the ending value for the range, usually something like n.
  • To the right is some function to evaluate for each value of the bound variable. In this case, a generic function, f(i).

This is read as “sum f ( i ) for i in the range 0 to n”.

One common definition of \Sigma uses a “closed” range; one that includes the end values of 0 and n. This is not a helpful definition for software; therefore, we will use a “half-open interval”. It has exactly n items, including 0 and n-1; mathematically, 0 \leq i < n.

Consequently, we prefer the following notation. It has the bound variable and the range of values written below. It has the function we’re evaluating written to the right.

\sum_{0 \leq i < n} f(i)

Since statistical and mathematical texts often used 1-based indexing, some care is required when translating formulae from textbooks to programming languages that use 0-based indexing.

Statistical Algorithms. Our statistical algorithms will be looking at data in lists (or tuples). In this case, the variable x is a sequence of some kind, and the index (i) is an index to select individual values from the sequence.

\sum_{0 \leq i < n} x_i

Sometimes, we’ll apply some function, f(), to each value of an array.

\sum_{0 \leq i < n} f(x_i)

Translating to Python. We can transform this definition directly into a for loop that sets the bound variable to all of the values in the range, and does some processing on each value of a sequence of integers.

This is the Python implementation of \Sigma. This computes two values, the sum, sum and the number of items, n.

Sigma Using a Numeric Index

sum= 0
for i in range(len(aTuple)):
    x_i= aTuple[i]
    # fxi = some function of x_i
    sum += x_i
n= len(aTuple)
  1. Get the length of aTuple. Execute the body of the loop for all values of i in the range 0 to the number of items-1.

  2. Fetch item i from aTuple and assign it to x_i.

  3. For simple mean calculation, the fxi statement does nothing.

    For a standard deviation calculation, we’d add a statement a fxi to compute the measure of deviation from the average.

  4. Sum the x_i (or fxi) values.

Simplification. In the usual mathematical notation, an integer index, i is used. In Python it isn’t necessary to use the formal integer index. Instead, an iterator can be used to visit each item of the list, without actually using an explicit numeric counter. The processing simplifies to the following.

Sigma Using an Iterator

for x_i in aTuple:
    # fxi = some function of x_i
    sum += x_i
n= len(aTuple)
  1. Execute the loop assigning each item of aTuple to x_i.

  2. For simple mean calculation, the fxi statement does nothing.

    For a standard deviation calculation, we’d add a statement a fxi to compute the measure of deviation from the average.

  3. Sum the x_i (or fxi) values.

Example. Here’s an example of computing a sum. We’re using the 6:00 AM temperatures this week as our sample data. We created a tuple with the unimaginative name of data for holding this tuple of temperatures.

>>> data = ( 8, 10, 12, 8, 6 )
>>> sum= 0
>>> for d in data:
...     sum += d
...
>>> sum
44
>>> sum/len(data)
8

Our for statement iterated through the data. The suite within the for statement added the data values into our accumulator, sum. The sum divided by the count is the mean.

To get precise results, be sure to use from __future__ import division.

Tuple Exercises

  1. Blocks of Stock.

    A block of stock as a number of attributes, including as purchase date, a purchase price, a number of shares, and a ticker symbol. We can record these pieces of information in a tuple for each block of stock and do a number of simple operations on the blocks.

    Let’s dream that we have the following portfolio.

    Purchase Date

    Purchase Price

    Shares

    Symbol

    Current Price

    25 Jan 2001

    43.50

    25

    CAT

    92.45

    25 Jan 2001

    42.80

    50

    DD

    51.19

    25 Jan 2001

    42.10

    75

    EK

    34.87

    25 Jan 2001

    37.58

    100

    GM

    37.58

    We can represent each block of stock as a 5-tuple with purchase date, purchase price, shares, ticker symbol and current price. We can create a list of those tuples, as follows.

    portfolio= [ ( "25-Jan-2001", 43.50, 25, 'CAT', 92.45 ),
    ( "25-Jan-2001", 42.80, 50, 'DD', 51.19 ),
    ( "25-Jan-2001", 42.10, 75, 'EK', 34.87 ),
    ( "25-Jan-2001", 37.58, 100, 'GM', 37.58 )
    ]
    

    Develop a function that examines a tuple which represents a block of stock, multiplies shares by purchase price and returns the value of that block. The sum of these values is the total purchase price of the portfolio.

    This function would have the following definition:

    def cost( aBlock ):
        compute price times shares
        return cost
    

    Develop a second function that examines a tuple which represents a block of stock, multiplies shares by purchase price and shares by a current price to determine the total amount gained or lost by this block.

    This function would have the following definition:

    def roi( aBlock, priceToday ):
        use cost( aBlock ) to get cost
    
        compute priceToday times shares
    
        return the difference
    
  2. Computing the Mean.

    Computing the mean of a list of values is relatively simple. The mean is the sum of the values divided by the number of values in the list. Since the statistical formula is so closely related to the actual loop, we’ll provide the formula, followed by an overview of the code.

    \mu_x = \dfrac{\sum\limits_{0 \le i < n} x_i}{n}

    [The cryptic-looking \mu_x is a short-hand for “mean of variable x”.]

    You can find the definition of the \Sigma mathematical operator in Translating From Math To Python: Conjugating The Verb “To Sigma”. From this, we can develop the following method for computing the mean:

    Computing Mean

    1. Initialize. Set sum, s, to zero

    2. Reduce. For each value, i, in the range 0 to the number of values in the list, n:

      add item x i to s

    3. Result. Return s \div n.

  1. Computing the Standard Deviation.

    The standard deviation can be done a few ways, but we’ll use the formula shown below. This computes a deviation measurement as the square of the difference between each sample and the mean. The sum of these measurements is then divided by the number of values times the number of degrees of freedom to get a standardized deviation measurement.

    Again, the formula summarizes the loop, so we’ll show the formula followed by an overview of the code.

    \sigma_x = \sqrt{ \dfrac{\sum\limits_{0 \leq i < n} (x_i - \mu_x)^2}{n-1} }

    [The cryptic-looking \sigma_x is short-hand for “standard deviation of variable x”.]

    You can find the definition of the \Sigma mathematical operator in Translating From Math To Python: Conjugating The Verb “To Sigma”. From this, we can develop the following method for computing the standard deviation:

    Computing Standard Deviation

    1. Initialize. Compute the mean, m.

      Initialize sum, s, to zero.

    2. Reduce. For each value, x i in the list:

      Compute the difference from the mean, d \gets x_i - \mu_x.

      Add d^2 to s.

    3. Variance. Compute the variance as \frac{s}{n-1}. The n- 1 factor reflects the statistical notion of “degrees of freedom”, which is beyond the scope of this book.

    4. Standard Deviation. Return the square root of the variance.

    The math module contains the math.sqrt(). For some additional information, see The math Module – Trig and Logs.

Table Of Contents

Previous topic

Sequences of Characters : str and Unicode

Next topic

Flexible Sequences : The list

This Page