# Python informer

## Lists

k = [1, 3, 5]       # a list is a sequence of values
m = [7]             # a list with just one element
n = []              # an empty list (no elements)
p = ['a', 3, 2.9]   # list can contain mixed types

x = [1, 2] + [7, 8]     # -> [1, 2, 7, 8] lists can be added
y = [0]*5               # -> [0, 0, 0, 0, 0] or multiplied
z = [5, 3]*3            # -> [5, 3, 5, 3, 5, 3]


## Tuples

#
# A tuple is like a list but it is immutable
# (the contents of a tuple cannot be changed after creating it)
#

t = (1, 3, 5)       # a tuple is a sequence of values
m = (7,)            # a tuple with just one element - comma required
v = (7)             # -> 7 (without the comma, it is just
#       a number in brackets)
n = ()              # an empty tuple (no elements)
p = ('a', 3, 2.9)   # tuple can contain mixed types

x = (1, 2) + (7, 8)     # -> (1, 2, 7, 8) tuples can be added
y = (0)*5               # -> (0, 0, 0, 0, 0) or multiplied
z = (5, 3)*3            # -> (5, 3, 5, 3, 5, 3)


#
# Reading elements works similarly for lists or tuples
# First lists:
#

k = [1, 3, 5]
k[0]                # -> 1 (the first element,
#       elements are numbered from 0)
k[2]                # -> 5 (the third element)
k[3]                # ERROR, there is no fourth element

k[-1]               # 5 (the last element, short for len-1)
k[-2]               # 3 (the second to last element, short for len-2)

#
# Tuples are the same:
#

t = (1, 3, 5)
t[0]                # -> 1 (the first element,
#       elements are numbered from 0)
t[2]                # -> 5 (the third element)
t[3]                # ERROR, there is no fourth element

t[-1]               # 5 (the last element, short for len-1)
t[-2]               # 3 (the second to last element, short for len-2)

#
# Reading slices (also works for tuples in the same way)
#

m = [2, 4, 6, 8]
m[1:3]              # [4, 6] (reads from element 1 up to
#         but not including element 3)
m[2:]               # [6, 8] (reads from element 2 to the end)
m[:3]               # [2, 4, 6] (reads from start up to
#            but not including element 3)
m[:]                # [2, 4, 6, 8] (reads from start to end)

y = x[:]            # creates a shallow copy of x and assigns to y
# if x is a list it creates a list
# if x is a tuple it creates a tuple

lst = [1, 2, 3, 4, 5, 6, 7, 8]
lst[1:6:2]          # [2, 4, 6] (reads from element 1 up to but not
#            including element 6, in steps of 2)
lst[5:2:-1]         # [6, 5, 4] (reads from element 5 down to but not
#            including element 2, in steps of -1)
lst[::-1]           # Counts from the end of the list to the start of
# the list is steps of -1, ie it creates a
# reversed copy [8, 7, 6, 5, 4, 3, 2, 1]


## Functions that work with lists and tuples

#
# Functions that return information about a sequence will
# work with lists or tuples
#

k = [1, 3, 2, 1, 2, 5]

len(k)              # -> 6 the length of the list/tuple
k.count(1)          # -> 2 (the value 1 appears 2 times in k)
k.count(8)          # -> 0 (the value 8 isn't in k)
1 in k              # -> True (1 appears in k at least once)
8 in k              # -> False (8 does not appear in k)
k.index(3)          # -> 1 (value 3 first appears at position 1)
k.index(2, 3)       # -> 4 (searches for the first value 2 in the
#       list from position 3 onwards)
k.index(1, 2, 4)    # -> 3 (searches for the first value 1 in the
#       list between positions 2 and 4)
k.index(7)          # ValueError (because 7 is not present)
k.copy()            # creates a shallow copy of the list or tuple



## Tuple packing and unpacking

#
# These only work with tuples (except unpacking works with lists too)
#

t = 1, 2            # creates a tuple (1, 2)
u = 5,              # creates a tuple (5,)
v = ()              # there is no packing syntax for empty tuples

a, b = t            # unpacks t into a and b: sets a = 1, b = 2
# the number of variables must match the number of
# values in the tuple
# this also works with lists
w = (5, 6, 7, 8)
a, *b, c = w        # set a = 5, b = [6, 7], c = 8
# *b takes all spare values as a list

x, y = 1, 2         # multiple assignment, sets x = 1, y = 2
# actually 1, 2 is packed into a tuple
# then unpacked

x, y = y, x         # swap values of x and y
# actually x, y is packed into a tuple
# then unpacked in swapped order



## List only functions

#
# These functions modify the list, so cannot be used with tuples
#

k = [1, 3, 5, 7, 9]
k[1] = 4            # k -> [1, 4, 5, 7, 9]
# sets value of element 1
k[1:4] = [0, 0, 0]  # k -> [1, 0, 0, 0, 9]
# replace a slice with new values

k.append(9)         # k -> [1, 7, 5, 9] (adds value to end of list)

k.extend([10, 11, 12])  # k -> [1, 7, 5, 9, 10, 11, 12]
# joins sequence to end of list

m = [0, 0, 0]
m.insert(1, 5)      # m -> [0, 5, 0, 0]
# insert 5 at index 1
m.insert(0, 6)      # m -> [6, 0, 5, 0, 0]
# insert 6 at start (index 0)
m.insert(len(m), 7) # m -> [6, 0, 5, 0, 0, 7]
# insert 7 at end (index len(m))

n = [2, 4, 6, 4, 8, 10]
n.remove(4)         # n -> [2, 6, 4, 8, 10]
# remove first element with value 4
n.pop()             # -> 10
# n -> [2, 6, 4, 8]
# removes last element and returns its value
n.pop(2)            # -> 4
# n -> [2, 6, 8]
# removes element at index and returns its value
n.clear()           # n -> [] (clear all elements)

p = [10, 11, 12, 13, 14]
del p[1]            # p -> [10, 12, 13, 14]
# remove element 1
# similar to pop but doesn't return a value
del p[1:4]          # p -> [10, 14]
# remove a slice
del p[:]            # p -> []
# remove all elments, equivalent to clear