Tuples

Dr Andy Evans

[Fullscreen]

Enclosing delimiters

  • Python uses three style of special enclosing delimiters. These are what the Python documentation calls them:
    • {} braces # Sometimes called curly brackets elsewhere.
    • [] brackets # Sometimes called square brackets elsewhere.
    • () parentheses # Sometimes called curved brackets elsewhere.

Holding more than one thing

  • What happens if we want to store more than one thing?
  • What happens if we want to store 10000 data points? We don't want to have to call each by a new name.
  • Languages generally have variables that are arrays: one variable that can store multiple things with one name and a numerical index. Here's one in Java:
    Assignment:
    array_name[3] = 21;

    Subscription (sometimes called indexing):
    System.out.print (array_name[3]);

Out of range

  • Depending on the language and data stored, the array will either refer to a space in memory where all the literals are stored, or will contain pointers (memory addresses) or references (linked labels) to their locations in memory (in Python it is generally the later).
  • Attempts to read a cell that doesn't exist will usually generate some kind of error message (usually "Index out of range/bounds" or similar) and end the program.

Arrays

  • As arrays can be very large, they usually require manifest typing - you have to say what they are going to hold (and sometimes how large they will be) to build them.
  • Python arrays need manifest typing. Python arrays are in a special module. You'd make one like this:
    import array
    a = array.array('i',[0,0,0,0]) # Signed int type 'i'
    a.insert(3, 21)
    print(a[3])

    Unlike many arrays, you don't need to say how big it will be.

Arrays

  • Arrays are very efficient: they are memory optimised for space and often for searching.
  • However, in general in most languages they aren't very easy to use:
    • You can only put pre-defined data types in them (usually just one)
    • In most languages (though not Python) they have a fixed size
    (in Python, stuff just gets added to the end whatever the index, though attempts to read non-existent cells still generates errors).
  • Because of this, most languages have wrappers for arrays that make them more flexible. In Python, these objects are called Containers, and much more used than arrays.

Containers

  • The container depends on how data is to be accessed, and whether it can be altered or not.
  • We will mainly be dealing with those in bold.
Data changeable:"Mutables" Data fixed: "Immutables"
Access by position:"Sequences" List Tuple; String; Bytes
Access by name: "Mappings" Dictionary Named tuple
Access by checking existence: "Sets" Set Frozen set

Mutability

  • Mutability is whether data can be changed after it is stored in an object.
  • Immutable objects are more efficient, as the computer can optimise around them guaranteed they won't change. Obviously, though, not being able to change them is limiting.
  • Numbers and strings are immutable, though they may not seem it: if you assign a new value to a pre-existing label, the value is created anew.
  • Of the containers, strings and tuples are immutable. We'll see that a) strings are containers, and b) that tuples can be immutable, yet contain mutable objects. Dictionaries, sets, and lists are mutable.

Sequences

  • Have the advantage of being a sequence (usually the sequence as added, but potentially ordered).
  • Their length is found with a builtin function, thus:
    len(sequence_name)
    a = len(seq) #e.g
  • Just like arrays, we refer to the values in them using a name and position index:
    name[i] # Where i is an int.
    print(seq[2]) # e.g.
  • All indices start with zero and go to len(sequence_name) - 1
0 1 2 ... len(sequence) - 1

Sequences

  • Tuples: immutable sequence of objects, either literal-style or more complicated objects.
  • Lists: mutable sequence of objects, either literal-style or more complicated objects.
  • Both can contain other sequences as their objects, and both can contain mixed types of object, so, for example ints and strings.

Tuples

  • Tuples are produced by the comma operator if used without [] {} enclosers. For example:
    a = 2,3
  • Frequently they are inside (), but this is only necessary for making the empty tuple:
    a = (2,3)
    a = ()
  • The following is a tuple with one element (the documentation calls this a singleton, though beware this has other, more general meanings):
    a = 2,
  • You can also use a constructor function:
    a = tuple(some_other_collection)

Tuples

  • You can also add and multiply tuples (but not subtract from them or divide):
    >>> a = 1,2,3
    >>> a = a + (4,) # or a += 4,
    >>> a
    (1, 2, 3, 4)

    >>> a = 1,2,3
    >>> a = a*2 # or a *= 2
    >>> a
    (1,2,3,1,2,3)

Subscription

  • You can get values out, thus:
    a[0] # First
    a[len(a) - 1] # Last

    But also:
    a[-1] # Last
    a[-len(a)] # First
  • Negatives count back from the end (essentially negatives get len()added to them).

Packing

  • Forcing multiple answers into a sequence is known as 'packing'.
  • Example: the divmod() builtin function returns a tuple (a // b, a % b)

    >>> c = divmod (9,2)
    >>> type(c)
    # c is automatically made tuple type
    >>> c[0] # subscription, cell 0
    4 # 9//2
    >>> c[1] # subscription, cell 1
    1 # 9%2

Unpacking

  • Unpacking is splitting a sequence across variables:
    >>> a = (1,2)
    >>> b, c = a
    >>> b
    1
    >>> c
    2
  • There must be the right number of variables to unpack into.
    Relatively rare in other languages, so feels Pythonic.

Packing/Unpacking

  • This packing/unpacking means you can assign multiple variables at once:
    a, b = 1, 2
  • But also means you can do this:
    a, b = divmod(9,2)
  • If you see two variable names with a comma between, they are usually being assigned some unpacked sequence.
  • You can find out what type with:
    >>> c = divmod(9,2)
    >>> type(c)
    or
    >>> type(divmod(9,2))
    Which returns the sequence (here a tuple) and passes it straight to the type function.

Example

  • >>> # Fibonacci series
    >>> # the sum of two elements
          defines the next
    >>> a, b = 0, 1
    >>> while b < 10:
    ...    print(b)
    ...    a, b = b, a+b

Ranges

  • Ranges are a special type of immutable sequence.
    range(start, stop, step) # Elements in italics optional
    Start; stop; step should be ints.
    Default for start = 0
    Default for step = 1
    Generates numbers up to but not including stop.
    range(4) # generates 0,1,2,3
    Note how this is the same as sequence indices - this will come in useful.
    range(2,8,2) generates 2,4,6
    range(0,-5,-1) generates 0,-1,-2,-3,-4

Tuple constructor

  • One way to make a tuple is thus:
    a = tuple(x) # Where x is a sequence or producer of a sequence
    >>> a = tuple(range(5))
    >>> a
    (0,1,2,3,4)
  • Note you can't just assign a label:
    >>> a = range(5)
    >>> a
    'range(0,5)'
    >>> type(a)
    <class 'range'>

Sequence functions

  • min(a) # Smallest item in a.
    max(a) # Largest item in a.
    a.index(x,i,j)
    # Index of the first occurrence of x in a
    #(at or after optional index i and before index j).
    a.count(x) # Counts of x in a.
    any(a)
    # For a sequence of Booleans, checks whether
    # any are true. Returns as soon as it finds
    # one (likewise, because of conversion,
    # whether any numbers are != 0)