diff --git a/getting_started/01_basics.ipynb b/getting_started/01_basics.ipynb
index 4caa7fb735b09a77b08786f69a0e5757f5ac6fbb..11cc06dce3e1220432f84ca70c8907ecb150d461 100644
--- a/getting_started/01_basics.ipynb
+++ b/getting_started/01_basics.ipynb
@@ -57,16 +57,24 @@
     "* strings\n",
     "* tuples\n",
     "* lists\n",
-    "* dictionary\n",
+    "* dictionaries\n",
     "\n",
     "N-dimensional arrays and other types are supported through common modules (e.g., numpy, scipy, scikit-learn).  These will be covered in a subsequent exercise."
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
+   "execution_count": 130,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "4\n"
+     ]
+    }
+   ],
    "source": [
     "a = 4\n",
     "b = 3.6\n",
@@ -85,9 +93,19 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
+   "execution_count": 131,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "[10, 20, 30]\n",
+      "{'b': 20, 'a': 10}\n",
+      "4 3.6 abc\n"
+     ]
+    }
+   ],
    "source": [
     "print(d)\n",
     "print(e)\n",
@@ -117,9 +135,17 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
+   "execution_count": 132,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "test string  ::  another test string\n"
+     ]
+    }
+   ],
    "source": [
     "s1 = \"test string\"\n",
     "s2 = 'another test string'\n",
@@ -135,9 +161,20 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
+   "execution_count": 133,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "This is\n",
+      "a string over\n",
+      "multiple lines\n",
+      "\n"
+     ]
+    }
+   ],
    "source": [
     "s3 = '''This is\n",
     "a string over\n",
@@ -158,9 +195,18 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
+   "execution_count": 134,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "The numerical value is 1 and a name is PyTreat\n",
+      "A name is PyTreat and a number is 1\n"
+     ]
+    }
+   ],
    "source": [
     "x = 1\n",
     "y = 'PyTreat'\n",
@@ -183,9 +229,18 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
+   "execution_count": 135,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "THIS IS A TEST STRING\n",
+      "this is a test string\n"
+     ]
+    }
+   ],
    "source": [
     "s = 'This is a Test String'\n",
     "print(s.upper())\n",
@@ -201,9 +256,17 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
+   "execution_count": 136,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "This is a Better String\n"
+     ]
+    }
+   ],
    "source": [
     "s = 'This is a Test String'\n",
     "s2 = s.replace('Test', 'Better')\n",
@@ -219,9 +282,17 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
+   "execution_count": 137,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "This is a Test String :: This is a Better String\n"
+     ]
+    }
+   ],
    "source": [
     "s3 = s + ' :: ' + s2\n",
     "print(s3)"
@@ -236,9 +307,17 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
+   "execution_count": 138,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "This is an example of an example String\n"
+     ]
+    }
+   ],
    "source": [
     "import re\n",
     "s = 'This is a test of a Test String'\n",
@@ -250,7 +329,7 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "where the `r` before the quote is used to force the regular expression specification to be a `raw string`.\n",
+    "where the `r` before the quote is used to force the regular expression specification to be a `raw string` (see [here](https://docs.python.org/3.5/library/re.html) for more info).\n",
     "\n",
     "For more information on matching and substitutions, look up the regular expression module on the web.\n",
     "\n",
@@ -259,9 +338,18 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
+   "execution_count": 139,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "*   A very    spacy   string       *\n",
+      "*A very    spacy   string*\n"
+     ]
+    }
+   ],
    "source": [
     "s2 = '   A very    spacy   string       '\n",
     "print('*' + s2 + '*')\n",
@@ -277,9 +365,18 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
+   "execution_count": 140,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "['This', 'is', 'a', 'test', 'of', 'a', 'Test', 'String']\n",
+      "['A', 'very', 'spacy', 'string']\n"
+     ]
+    }
+   ],
    "source": [
     "print(s.split())\n",
     "print(s2.split())"
@@ -294,9 +391,17 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
+   "execution_count": 141,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "['  This is', '  as you can    see ', '   a very  weirdly spaced and punctuated    string ...  ']\n"
+     ]
+    }
+   ],
    "source": [
     "s4 = '  This is,  as you can    see ,   a very  weirdly spaced and punctuated    string ...  '\n",
     "print(s4.split(','))"
@@ -315,9 +420,19 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
+   "execution_count": 142,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "232.03\n",
+      "25.03\n",
+      "25.03\n"
+     ]
+    }
+   ],
    "source": [
     "sint='23'\n",
     "sfp='2.03'\n",
@@ -341,14 +456,23 @@
     "but for numerical vectors and arrays it is much better to use _numpy_\n",
     "arrays (or matrices), which are covered in a later tutorial.\n",
     "\n",
-    "A tuple is like a list or a vector, but with less flexibility than a full list, however anything can be stored in either a list or tuple, without any consistency being required.  For example:"
+    "A tuple is like a list or a vector, but with less flexibility than a full list (tuples are immutable), however anything can be stored in either a list or tuple, without any consistency being required.  Tuples are defined using round brackets and lists are defined using square brackets. For example:"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
+   "execution_count": 143,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "(3, 7.6, 'str')\n",
+      "[1, 'mj', -5.4]\n"
+     ]
+    }
+   ],
    "source": [
     "xtuple = (3, 7.6, 'str')\n",
     "xlist = [1, 'mj', -5.4]\n",
@@ -365,9 +489,18 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
+   "execution_count": 144,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "x2 is:  ((3, 7.6, 'str'), [1, 'mj', -5.4])\n",
+      "x3 is:  [(3, 7.6, 'str'), [1, 'mj', -5.4]]\n"
+     ]
+    }
+   ],
    "source": [
     "x2 = (xtuple, xlist)\n",
     "x3 = [xtuple, xlist]\n",
@@ -387,9 +520,17 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
+   "execution_count": 145,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "[10, 20, 30, 70, 80]\n"
+     ]
+    }
+   ],
    "source": [
     "a = [10, 20, 30]\n",
     "a = a + [70]\n",
@@ -401,17 +542,27 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
+    "> Similar things can be done for tuples, except for the last one: that is, a += (80) as a tuple is immutable so cannot be changed like this. \n",
+    "\n",
     "<a class=\"anchor\" id=\"Indexing\"></a>\n",
     "### Indexing\n",
     "\n",
-    "Square brackets are used to index tuples, lists, dictionaries, etc.  For example:"
+    "Square brackets are used to index tuples, lists, strings, dictionaries, etc.  For example:"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
+   "execution_count": 146,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "20\n"
+     ]
+    }
+   ],
    "source": [
     "d = [10, 20, 30]\n",
     "print(d[1])"
@@ -427,9 +578,18 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
+   "execution_count": 147,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "10\n",
+      "30\n"
+     ]
+    }
+   ],
    "source": [
     "a = [10, 20, 30, 40, 50, 60]\n",
     "print(a[0])\n",
@@ -445,9 +605,18 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
+   "execution_count": 148,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "60\n",
+      "10\n"
+     ]
+    }
+   ],
    "source": [
     "print(a[-1])\n",
     "print(a[-6])"
@@ -462,18 +631,42 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
+   "execution_count": 149,
+   "metadata": {},
+   "outputs": [
+    {
+     "ename": "IndexError",
+     "evalue": "list index out of range",
+     "output_type": "error",
+     "traceback": [
+      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+      "\u001b[0;31mIndexError\u001b[0m                                Traceback (most recent call last)",
+      "\u001b[0;32m<ipython-input-149-f4cf4536701c>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0ma\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m-\u001b[0m\u001b[0;36m7\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
+      "\u001b[0;31mIndexError\u001b[0m: list index out of range"
+     ]
+    }
+   ],
    "source": [
     "print(a[-7])"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
+   "execution_count": 150,
+   "metadata": {},
+   "outputs": [
+    {
+     "ename": "IndexError",
+     "evalue": "list index out of range",
+     "output_type": "error",
+     "traceback": [
+      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+      "\u001b[0;31mIndexError\u001b[0m                                Traceback (most recent call last)",
+      "\u001b[0;32m<ipython-input-150-52d95fbe5286>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0ma\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m6\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
+      "\u001b[0;31mIndexError\u001b[0m: list index out of range"
+     ]
+    }
+   ],
    "source": [
     "print(a[6])"
    ]
@@ -487,9 +680,17 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
+   "execution_count": 151,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "6\n"
+     ]
+    }
+   ],
    "source": [
     "print(len(a))"
    ]
@@ -503,9 +704,18 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
+   "execution_count": 152,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "20\n",
+      "40\n"
+     ]
+    }
+   ],
    "source": [
     "b = [[10, 20, 30], [40, 50, 60]]\n",
     "print(b[0][1])\n",
@@ -516,7 +726,7 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "but *not* an index like b[0, 1].\n",
+    "but *not* an index like `b[0, 1]`. However, numpy arrays (covered in a later practical) can be indexed like `b[0, 1]` and similarly for higher dimensions.\n",
     "\n",
     "> Note that `len` will only give the length of the top level.\n",
     "> In general, numpy arrays should be preferred to nested lists when the contents are numerical.\n",
@@ -529,9 +739,17 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
+   "execution_count": 153,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "[10, 20, 30]\n"
+     ]
+    }
+   ],
    "source": [
     "print(a[0:3])"
    ]
@@ -548,9 +766,18 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
+   "execution_count": 154,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "[10, 20, 30]\n",
+      "[20, 30]\n"
+     ]
+    }
+   ],
    "source": [
     "a = [10, 20, 30, 40, 50, 60]\n",
     "print(a[0:3])    # same as a(1:3) in MATLAB\n",
@@ -569,9 +796,21 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
+   "execution_count": 155,
+   "metadata": {},
+   "outputs": [
+    {
+     "ename": "TypeError",
+     "evalue": "list indices must be integers or slices, not list",
+     "output_type": "error",
+     "traceback": [
+      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+      "\u001b[0;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
+      "\u001b[0;32m<ipython-input-155-aad7915ae3d8>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[1;32m      1\u001b[0m \u001b[0mb\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;36m3\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m4\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0ma\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mb\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
+      "\u001b[0;31mTypeError\u001b[0m: list indices must be integers or slices, not list"
+     ]
+    }
+   ],
    "source": [
     "b = [3, 4]\n",
     "print(a[b])"
@@ -581,6 +820,67 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
+    "In python you can leave the start and end values implicit, as it will assume these are the beginning and the end.  For example:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 156,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "[10, 20, 30]\n",
+      "[20, 30, 40, 50, 60]\n",
+      "[10, 20, 30, 40, 50]\n"
+     ]
+    }
+   ],
+   "source": [
+    "print(a[:3])\n",
+    "print(a[1:])\n",
+    "print(a[:-1])"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "in the last example remember that negative indices are subject to wrap around so that `a[:-1]` represents all elements up to the penultimate one.\n",
+    "\n",
+    "You can also change the step size, which is specified by the third value (not the second one, as in MATLAB).  For example:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 157,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "[10, 30]\n",
+      "[10, 30, 50]\n",
+      "[60, 50, 40, 30, 20, 10]\n"
+     ]
+    }
+   ],
+   "source": [
+    "print(a[0:4:2])\n",
+    "print(a[::2])\n",
+    "print(a[::-1])"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "the last example is a simple way to reverse a sequence.\n",
+    "\n",
+    "\n",
     "<a class=\"anchor\" id=\"List-operations\"></a>\n",
     "### List operations\n",
     "\n",
@@ -589,9 +889,17 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
+   "execution_count": 158,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "[10, 20, 30, 10, 20, 30, 10, 20, 30, 10, 20, 30]\n"
+     ]
+    }
+   ],
    "source": [
     "d = [10, 20, 30]\n",
     "print(d * 4)"
@@ -606,12 +914,28 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
+   "execution_count": 159,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "[10, 20, 30, 40]\n",
+      "[10, 20, 30, 40, 50, 60]\n",
+      "[10, 20, 30, 40, 50, 60, 70, 80]\n",
+      "[10, 30, 40, 50, 60, 70, 80]\n",
+      "[30, 40, 50, 60, 70, 80]\n"
+     ]
+    }
+   ],
    "source": [
     "d.append(40)\n",
     "print(d)\n",
+    "d.extend([50, 60])\n",
+    "print(d)\n",
+    "d = d + [70, 80]\n",
+    "print(d)\n",
     "d.remove(20)\n",
     "print(d)\n",
     "d.pop(0)\n",
@@ -622,15 +946,27 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
+    "> Note that `d.append([50,60])` would run but instead of adding two extra elements it only adds a single element, where this element is a list of length two, making a messy list. Try it and see if this is not clear.\n",
+    "\n",
     "<a class=\"anchor\" id=\"Looping\"></a>\n",
     "### Looping over elements in a list (or tuple)"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
+   "execution_count": 160,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "10\n",
+      "20\n",
+      "30\n"
+     ]
+    }
+   ],
    "source": [
     "d = [10, 20, 30]\n",
     "for x in d:\n",
@@ -641,7 +977,7 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "> Note that the indentation within the loop is _*crucial*_.  All python control blocks are delineated purely by indentation.\n",
+    "> Note that the indentation within the loop is _*crucial*_.  All python control blocks are delineated purely by indentation. We recommend using **four spaces** and no tabs, as this is a standard practice and will help a lot when collaborating with others.\n",
     "\n",
     "<a class=\"anchor\" id=\"Getting-help\"></a>\n",
     "### Getting help\n",
@@ -651,9 +987,134 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
+   "execution_count": 161,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "Help on list object:\n",
+      "\n",
+      "class list(object)\n",
+      " |  list() -> new empty list\n",
+      " |  list(iterable) -> new list initialized from iterable's items\n",
+      " |  \n",
+      " |  Methods defined here:\n",
+      " |  \n",
+      " |  __add__(self, value, /)\n",
+      " |      Return self+value.\n",
+      " |  \n",
+      " |  __contains__(self, key, /)\n",
+      " |      Return key in self.\n",
+      " |  \n",
+      " |  __delitem__(self, key, /)\n",
+      " |      Delete self[key].\n",
+      " |  \n",
+      " |  __eq__(self, value, /)\n",
+      " |      Return self==value.\n",
+      " |  \n",
+      " |  __ge__(self, value, /)\n",
+      " |      Return self>=value.\n",
+      " |  \n",
+      " |  __getattribute__(self, name, /)\n",
+      " |      Return getattr(self, name).\n",
+      " |  \n",
+      " |  __getitem__(...)\n",
+      " |      x.__getitem__(y) <==> x[y]\n",
+      " |  \n",
+      " |  __gt__(self, value, /)\n",
+      " |      Return self>value.\n",
+      " |  \n",
+      " |  __iadd__(self, value, /)\n",
+      " |      Implement self+=value.\n",
+      " |  \n",
+      " |  __imul__(self, value, /)\n",
+      " |      Implement self*=value.\n",
+      " |  \n",
+      " |  __init__(self, /, *args, **kwargs)\n",
+      " |      Initialize self.  See help(type(self)) for accurate signature.\n",
+      " |  \n",
+      " |  __iter__(self, /)\n",
+      " |      Implement iter(self).\n",
+      " |  \n",
+      " |  __le__(self, value, /)\n",
+      " |      Return self<=value.\n",
+      " |  \n",
+      " |  __len__(self, /)\n",
+      " |      Return len(self).\n",
+      " |  \n",
+      " |  __lt__(self, value, /)\n",
+      " |      Return self<value.\n",
+      " |  \n",
+      " |  __mul__(self, value, /)\n",
+      " |      Return self*value.n\n",
+      " |  \n",
+      " |  __ne__(self, value, /)\n",
+      " |      Return self!=value.\n",
+      " |  \n",
+      " |  __new__(*args, **kwargs) from builtins.type\n",
+      " |      Create and return a new object.  See help(type) for accurate signature.\n",
+      " |  \n",
+      " |  __repr__(self, /)\n",
+      " |      Return repr(self).\n",
+      " |  \n",
+      " |  __reversed__(...)\n",
+      " |      L.__reversed__() -- return a reverse iterator over the list\n",
+      " |  \n",
+      " |  __rmul__(self, value, /)\n",
+      " |      Return self*value.\n",
+      " |  \n",
+      " |  __setitem__(self, key, value, /)\n",
+      " |      Set self[key] to value.\n",
+      " |  \n",
+      " |  __sizeof__(...)\n",
+      " |      L.__sizeof__() -- size of L in memory, in bytes\n",
+      " |  \n",
+      " |  append(...)\n",
+      " |      L.append(object) -> None -- append object to end\n",
+      " |  \n",
+      " |  clear(...)\n",
+      " |      L.clear() -> None -- remove all items from L\n",
+      " |  \n",
+      " |  copy(...)\n",
+      " |      L.copy() -> list -- a shallow copy of L\n",
+      " |  \n",
+      " |  count(...)\n",
+      " |      L.count(value) -> integer -- return number of occurrences of value\n",
+      " |  \n",
+      " |  extend(...)\n",
+      " |      L.extend(iterable) -> None -- extend list by appending elements from the iterable\n",
+      " |  \n",
+      " |  index(...)\n",
+      " |      L.index(value, [start, [stop]]) -> integer -- return first index of value.\n",
+      " |      Raises ValueError if the value is not present.\n",
+      " |  \n",
+      " |  insert(...)\n",
+      " |      L.insert(index, object) -- insert object before index\n",
+      " |  \n",
+      " |  pop(...)\n",
+      " |      L.pop([index]) -> item -- remove and return item at index (default last).\n",
+      " |      Raises IndexError if list is empty or index is out of range.\n",
+      " |  \n",
+      " |  remove(...)\n",
+      " |      L.remove(value) -> None -- remove first occurrence of value.\n",
+      " |      Raises ValueError if the value is not present.\n",
+      " |  \n",
+      " |  reverse(...)\n",
+      " |      L.reverse() -- reverse *IN PLACE*\n",
+      " |  \n",
+      " |  sort(...)\n",
+      " |      L.sort(key=None, reverse=False) -> None -- stable sort *IN PLACE*\n",
+      " |  \n",
+      " |  ----------------------------------------------------------------------\n",
+      " |  Data and other attributes defined here:\n",
+      " |  \n",
+      " |  __hash__ = None\n",
+      "\n"
+     ]
+    }
+   ],
    "source": [
     "help(d)"
    ]
@@ -667,9 +1128,64 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
+   "execution_count": 162,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "['__add__',\n",
+       " '__class__',\n",
+       " '__contains__',\n",
+       " '__delattr__',\n",
+       " '__delitem__',\n",
+       " '__dir__',\n",
+       " '__doc__',\n",
+       " '__eq__',\n",
+       " '__format__',\n",
+       " '__ge__',\n",
+       " '__getattribute__',\n",
+       " '__getitem__',\n",
+       " '__gt__',\n",
+       " '__hash__',\n",
+       " '__iadd__',\n",
+       " '__imul__',\n",
+       " '__init__',\n",
+       " '__iter__',\n",
+       " '__le__',\n",
+       " '__len__',\n",
+       " '__lt__',\n",
+       " '__mul__',\n",
+       " '__ne__',\n",
+       " '__new__',\n",
+       " '__reduce__',\n",
+       " '__reduce_ex__',\n",
+       " '__repr__',\n",
+       " '__reversed__',\n",
+       " '__rmul__',\n",
+       " '__setattr__',\n",
+       " '__setitem__',\n",
+       " '__sizeof__',\n",
+       " '__str__',\n",
+       " '__subclasshook__',\n",
+       " 'append',\n",
+       " 'clear',\n",
+       " 'copy',\n",
+       " 'count',\n",
+       " 'extend',\n",
+       " 'index',\n",
+       " 'insert',\n",
+       " 'pop',\n",
+       " 'remove',\n",
+       " 'reverse',\n",
+       " 'sort']"
+      ]
+     },
+     "execution_count": 162,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
    "source": [
     "dir(d)"
    ]
@@ -678,7 +1194,7 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "> Note that google is often more helpful!\n",
+    "> Note that google is often more helpful!  At least, as long as you find pages relating to the right version of python - we use python 3 for FSL, so check that what you find is appropriate for that.\n",
     "\n",
     "---\n",
     "\n",
@@ -690,9 +1206,20 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
+   "execution_count": 163,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "2\n",
+      "dict_keys(['b', 'a'])\n",
+      "dict_values([20, 10])\n",
+      "10\n"
+     ]
+    }
+   ],
    "source": [
     "e = {'a' : 10, 'b': 20}\n",
     "print(len(e))\n",
@@ -707,7 +1234,7 @@
    "source": [
     "The keys and values can take on almost any type, even dictionaries!\n",
     "Python is nothing if not flexible.  However, each key must be unique\n",
-    "and the dictionary must be \"hashable\".\n",
+    "and [hashable](https://docs.python.org/3.5/glossary.html#term-hashable).\n",
     "\n",
     "<a class=\"anchor\" id=\"Adding-to-a-dictionary\"></a>\n",
     "### Adding to a dictionary\n",
@@ -717,9 +1244,17 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
+   "execution_count": 164,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "{'b': 20, 'a': 10, 'c': 555}\n"
+     ]
+    }
+   ],
    "source": [
     "e['c'] = 555   # just like in Biobank!  ;)\n",
     "print(e)"
@@ -737,9 +1272,18 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
+   "execution_count": 165,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "{'a': 10, 'c': 555}\n",
+      "{'a': 10}\n"
+     ]
+    }
+   ],
    "source": [
     "e.pop('b')\n",
     "print(e)\n",
@@ -759,13 +1303,23 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
+   "execution_count": 166,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "('b', 20)\n",
+      "('a', 10)\n",
+      "('c', 555)\n"
+     ]
+    }
+   ],
    "source": [
     "e = {'a' : 10, 'b': 20, 'c':555}\n",
     "for k, v in e.items():\n",
-    "   print((k, v))"
+    "    print((k, v))"
    ]
   },
   {
@@ -779,9 +1333,19 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
+   "execution_count": 167,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "('b', 20)\n",
+      "('a', 10)\n",
+      "('c', 555)\n"
+     ]
+    }
+   ],
    "source": [
     "for k in e:\n",
     "    print((k, e[k]))"
@@ -793,7 +1357,7 @@
    "source": [
     "> Note that in both cases the order is arbitrary. The `sorted` function can be used if you want keys in a sorted order; e.g. `for k in sorted(e):` ...\n",
     ">\n",
-    "> There are also other options if you want a dictionary with ordering.\n",
+    "> There are also [other options](https://docs.python.org/3.5/library/collections.html#collections.OrderedDict) if you want a dictionary with ordering.\n",
     "\n",
     "---\n",
     "\n",
@@ -805,9 +1369,17 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
+   "execution_count": 168,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "7\n"
+     ]
+    }
+   ],
    "source": [
     "a = 7\n",
     "b = a\n",
@@ -824,9 +1396,17 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
+   "execution_count": 169,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "[8888]\n"
+     ]
+    }
+   ],
    "source": [
     "a = [7]\n",
     "b = a\n",
@@ -843,9 +1423,17 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
+   "execution_count": 170,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "[7, 7]\n"
+     ]
+    }
+   ],
    "source": [
     "a = [7]\n",
     "b = a * 2\n",
@@ -862,9 +1450,17 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
+   "execution_count": 171,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "[7]\n"
+     ]
+    }
+   ],
    "source": [
     "a = [7]\n",
     "b = list(a)\n",
@@ -876,14 +1472,23 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "There is a constructor for each type and this con be useful for converting between types:"
+    "There is a constructor for each type and this can be useful for converting between types:"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
+   "execution_count": 172,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "(2, 5, 7)\n",
+      "[2, 5, 7]\n"
+     ]
+    }
+   ],
    "source": [
     "xt = (2, 5, 7)\n",
     "xl = list(xt)\n",
@@ -902,25 +1507,44 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
+   "execution_count": 173,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "a:  [5]\n",
+      "x:  [5, 10]\n",
+      "a:  [5, 10]\n",
+      "x:  [5, 10, 10]\n",
+      "a:  [5, 10]\n",
+      "return value:  [5, 10, 10]\n",
+      "a:  [5, 10]\n",
+      "b:  [5, 10, 10]\n"
+     ]
+    }
+   ],
    "source": [
     "def foo1(x):\n",
-    "   x.append(10)\n",
+    "    x.append(10)\n",
+    "    print('x: ', x)\n",
     "def foo2(x):\n",
-    "   x = x + [10]\n",
+    "    x = x + [10]\n",
+    "    print('x: ', x)\n",
     "def foo3(x):\n",
-    "   return x + [10]\n",
+    "    print('return value: ', x + [10])\n",
+    "    return x + [10]\n",
     "\n",
     "a = [5]\n",
-    "print(a)\n",
+    "print('a: ', a)\n",
     "foo1(a)\n",
-    "print(a)\n",
+    "print('a: ', a)\n",
     "foo2(a)\n",
-    "print(a)\n",
-    "foo3(a)\n",
-    "print(a)"
+    "print('a: ', a)\n",
+    "b = foo3(a)\n",
+    "print('a: ', a)\n",
+    "print('b: ', b)"
    ]
   },
   {
@@ -948,9 +1572,21 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
+   "execution_count": 174,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "Not a is: False\n",
+      "Not 1 is: False\n",
+      "Not 0 is: True\n",
+      "Not {} is: True\n",
+      "{}==0 is: False\n"
+     ]
+    }
+   ],
    "source": [
     "a = True\n",
     "print('Not a is:', not a)\n",
@@ -969,9 +1605,19 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
+   "execution_count": 175,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "False\n",
+      "True\n",
+      "True\n"
+     ]
+    }
+   ],
    "source": [
     "print('the' in 'a number of words')\n",
     "print('of' in 'a number of words')\n",
@@ -982,6 +1628,9 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
+    "A useful keyword is `None`, which is a bit like \"null\". This can be a default value for a variable and should be tested with the `is` operator rather than `==` (for technical reasons that it isn't worth going into here). For example: `a is None` or `a is not None` are the preferred tests.\n",
+    "\n",
+    "\n",
     "<a class=\"anchor\" id=\"If-statements\"></a>\n",
     "### If statements\n",
     "\n",
@@ -990,19 +1639,28 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
+   "execution_count": 176,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "0.5890515724950383\n",
+      "Positive\n"
+     ]
+    }
+   ],
    "source": [
     "import random\n",
     "a = random.uniform(-1, 1)\n",
     "print(a)\n",
     "if a>0:\n",
-    "   print('Positive')\n",
+    "    print('Positive')\n",
     "elif a<0:\n",
-    "   print('Negative')\n",
+    "    print('Negative')\n",
     "else:\n",
-    "   print('Zero')"
+    "    print('Zero')"
    ]
   },
   {
@@ -1014,13 +1672,21 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
+   "execution_count": 177,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "Variable is true, or at least not empty\n"
+     ]
+    }
+   ],
    "source": [
     "a = []    # just one of many examples\n",
     "if not a:\n",
-    "   print('Variable is true, or at least not empty')"
+    "    print('Variable is true, or at least not empty')"
    ]
   },
   {
@@ -1039,12 +1705,24 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
+   "execution_count": 178,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "2\n",
+      "is\n",
+      "more\n",
+      "than\n",
+      "1\n"
+     ]
+    }
+   ],
    "source": [
     "for x in [2, 'is', 'more', 'than', 1]:\n",
-    "   print(x)"
+    "    print(x)"
    ]
   },
   {
@@ -1058,9 +1736,23 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
+   "execution_count": 179,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "2\n",
+      "3\n",
+      "4\n",
+      "5\n",
+      "6\n",
+      "7\n",
+      "8\n"
+     ]
+    }
+   ],
    "source": [
     "for x in range(2, 9):\n",
     "  print(x)"
@@ -1077,9 +1769,18 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
+   "execution_count": 180,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "4\n",
+      "7\n"
+     ]
+    }
+   ],
    "source": [
     "x, y = [4, 7]\n",
     "print(x)\n",
@@ -1095,15 +1796,27 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
+   "execution_count": 181,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "[('Some', 0), ('set', 1), ('of', 2), ('items', 3)]\n",
+      "0 Some\n",
+      "1 set\n",
+      "2 of\n",
+      "3 items\n"
+     ]
+    }
+   ],
    "source": [
     "alist = ['Some', 'set', 'of', 'items']\n",
     "blist = list(range(len(alist)))\n",
     "print(list(zip(alist, blist)))\n",
     "for x, y in zip(alist, blist):\n",
-    "   print(y, x)"
+    "    print(y, x)"
    ]
   },
   {
@@ -1120,18 +1833,26 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
+   "execution_count": 182,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "34.995996566662235\n"
+     ]
+    }
+   ],
    "source": [
     "import random\n",
     "n = 0\n",
     "x = 0\n",
     "while n<100:\n",
-    "   x += random.uniform(0, 1)**2   # where ** is a power operation\n",
-    "   if x>50:\n",
-    "      break\n",
-    "   n += 1\n",
+    "    x += random.uniform(0, 1)**2   # where ** is a power operation\n",
+    "    if x>50:\n",
+    "        break\n",
+    "    n += 1\n",
     "print(x)"
    ]
   },
@@ -1141,6 +1862,8 @@
    "source": [
     "You can also use `continue` as in other languages.\n",
     "\n",
+    "> Note that there is no `do ... while` construct.\n",
+    "\n",
     "---\n",
     "\n",
     "<a class=\"anchor\" id=\"quick-intro\"></a>\n",
@@ -1158,9 +1881,17 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
+   "execution_count": 183,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "0.33573141209899227 0.11271558106998338\n"
+     ]
+    }
+   ],
    "source": [
     "import random\n",
     "x = random.uniform(0, 1)\n",
@@ -1180,9 +1911,18 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
+   "execution_count": 184,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]\n",
+      "[0, 1, 4, 9, 16, 25, 36, 64, 81]\n"
+     ]
+    }
+   ],
    "source": [
     "v1 = [ x**2 for x in range(10) ]\n",
     "print(v1)\n",
@@ -1219,14 +1959,24 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
+   "execution_count": 185,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "(22.360679774997898, 500)\n",
+      "37.416573867739416\n",
+      "37.416573867739416\n"
+     ]
+    }
+   ],
    "source": [
     "def myfunc(x, y, z=0):\n",
     "    r2 = x*x + y*y + z*z\n",
     "    r = r2**0.5\n",
-    "    return (r,  r2)\n",
+    "    return r,  r2\n",
     "\n",
     "rad = myfunc(10, 20)\n",
     "print(rad)\n",
@@ -1242,6 +1992,8 @@
    "source": [
     "> Note that the `_` is used as shorthand here for a dummy variable\n",
     "> that you want to throw away.\n",
+    ">\n",
+    "> The return statement implicitly creates a tuple to return and is equivalent to `return (r, r2)`\n",
     "\n",
     "One nice feature of python functions is that you can name the\n",
     "arguments when you call them, rather than only doing it by position.\n",
@@ -1250,16 +2002,24 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
+   "execution_count": 186,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "22.360679774997898 30 60\n"
+     ]
+    }
+   ],
    "source": [
     "def myfunc(x, y, z=0, flag=''):\n",
-    "   if flag=='L1':\n",
-    "       r = abs(x) + abs(y) + abs(z)\n",
-    "   else:\n",
-    "       r = (x*x + y*y + z*z)**0.5\n",
-    "   return r\n",
+    "    if flag=='L1':\n",
+    "        r = abs(x) + abs(y) + abs(z)\n",
+    "    else:\n",
+    "        r = (x*x + y*y + z*z)**0.5\n",
+    "    return r\n",
     "\n",
     "rA = myfunc(10, 20)\n",
     "rB = myfunc(10, 20, flag='L1')\n",
@@ -1271,7 +2031,7 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "You will often see python functions called with these named arguments.\n",
+    "You will often see python functions called with these named arguments. In fact, for functions with more than 2 or 3 variables this naming of arguments is recommended, because it clarifies what each of the arguments does for anyone reading the code.\n",
     "\n",
     "---\n",
     "\n",
@@ -1283,7 +2043,7 @@
     "\n",
     "Write some code to do the following: \n",
     " * separate out the filenames and ID codes into separate lists (ID's\n",
-    " should be numerical values, not strings)\n",
+    " should be numerical values, not strings) - you may need several steps for this\n",
     " * loop over the two and generate a _string_ that could be used to\n",
     "   rename the directories (e.g., `mv /vols/Data/pytreat/AAC /vols/Data/pytreat/S165873`) - we will cover how to actually execute these in a later practical\n",
     " * convert your dual lists into a dictionary, with ID as the key\n",
@@ -1300,7 +2060,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "mstr = '/vols/Data/pytreat/AAC, 165873,  /vols/Data/pytreat/AAG,   170285, /vols/Data/pytreat/AAH, 196792, /vols/Data/pytreat/AAK, 212577, /vols/Data/pytreat/AAQ, 385376, /vols/Data/pytreat/AB, 444600, /vols/Data/pytreat/AC6, 454578, /vols/Data/pytreat/V8, 501502,   /vols/Data/pytreat/2YK, 667688, /vols/Data/pytreat/C3PO, 821971'"
+    "mstr = '/vols/Data/pytreat/AAC, 165873,  /vols/Data/pytreat/AAG,   170285, /vols/Data/pytreat/AAH, 196792, /vols/Data/pytreat/AAK, 212577, /vols/Data/pytreat/AAQ, 385376, /vols/Data/pytreat/AB, 444600, /vols/Data/pytreat/AC6, 454578, /vols/Data/pytreat/V8, 501502,   /vols/Data/pytreat/2YK, 667688, /vols/Data/pytreat/C3PO, 821971'\n"
    ]
   }
  ],
diff --git a/getting_started/01_basics.md b/getting_started/01_basics.md
index 760f2c41de0963f9172f51179a675cd395513b84..9c5928de0ac64d057b56057096881f180d495089 100644
--- a/getting_started/01_basics.md
+++ b/getting_started/01_basics.md
@@ -51,7 +51,7 @@ Python has many different types and variables are dynamic and can change types (
 * strings
 * tuples
 * lists
-* dictionary
+* dictionaries
 
 N-dimensional arrays and other types are supported through common modules (e.g., numpy, scipy, scikit-learn).  These will be covered in a subsequent exercise.
 
@@ -146,7 +146,7 @@ s = 'This is a test of a Test String'
 s1 = re.sub(r'a [Tt]est', "an example", s)
 print(s1)
 ```
-where the `r` before the quote is used to force the regular expression specification to be a `raw string`.
+where the `r` before the quote is used to force the regular expression specification to be a `raw string` (see [here](https://docs.python.org/3.5/library/re.html) for more info).
 
 For more information on matching and substitutions, look up the regular expression module on the web.
 
@@ -195,7 +195,7 @@ Both tuples and lists are builtin python types and are like vectors,
 but for numerical vectors and arrays it is much better to use _numpy_
 arrays (or matrices), which are covered in a later tutorial.
 
-A tuple is like a list or a vector, but with less flexibility than a full list, however anything can be stored in either a list or tuple, without any consistency being required.  For example:
+A tuple is like a list or a vector, but with less flexibility than a full list (tuples are immutable), however anything can be stored in either a list or tuple, without any consistency being required.  Tuples are defined using round brackets and lists are defined using square brackets. For example:
 ```
 xtuple = (3, 7.6, 'str')
 xlist = [1, 'mj', -5.4]
@@ -222,10 +222,12 @@ a +=  [80]
 print(a)
 ```
 
+> Similar things can be done for tuples, except for the last one: that is, a += (80) as a tuple is immutable so cannot be changed like this. 
+
 <a class="anchor" id="Indexing"></a>
 ### Indexing
 
-Square brackets are used to index tuples, lists, dictionaries, etc.  For example:
+Square brackets are used to index tuples, lists, strings, dictionaries, etc.  For example:
 ```
 d = [10, 20, 30]
 print(d[1])
@@ -265,7 +267,7 @@ b = [[10, 20, 30], [40, 50, 60]]
 print(b[0][1])
 print(b[1][0])
 ```
-but *not* an index like b[0, 1].
+but *not* an index like `b[0, 1]`. However, numpy arrays (covered in a later practical) can be indexed like `b[0, 1]` and similarly for higher dimensions.
 
 > Note that `len` will only give the length of the top level.
 > In general, numpy arrays should be preferred to nested lists when the contents are numerical.
@@ -299,6 +301,23 @@ b = [3, 4]
 print(a[b])
 ```
 
+In python you can leave the start and end values implicit, as it will assume these are the beginning and the end.  For example:
+```
+print(a[:3])
+print(a[1:])
+print(a[:-1])
+```
+in the last example remember that negative indices are subject to wrap around so that `a[:-1]` represents all elements up to the penultimate one.
+
+You can also change the step size, which is specified by the third value (not the second one, as in MATLAB).  For example:
+```
+print(a[0:4:2])
+print(a[::2])
+print(a[::-1])
+```
+the last example is a simple way to reverse a sequence.
+
+
 <a class="anchor" id="List-operations"></a>
 ### List operations
 
@@ -313,12 +332,18 @@ There are also other operations such as:
 ```
 d.append(40)
 print(d)
+d.extend([50, 60])
+print(d)
+d = d + [70, 80]
+print(d)
 d.remove(20)
 print(d)
 d.pop(0)
 print(d)
 ```
 
+> Note that `d.append([50,60])` would run but instead of adding two extra elements it only adds a single element, where this element is a list of length two, making a messy list. Try it and see if this is not clear.
+
 <a class="anchor" id="Looping"></a>
 ### Looping over elements in a list (or tuple)
 
@@ -328,7 +353,7 @@ for x in d:
     print(x)
 ```
 
-> Note that the indentation within the loop is _*crucial*_.  All python control blocks are delineated purely by indentation.
+> Note that the indentation within the loop is _*crucial*_.  All python control blocks are delineated purely by indentation. We recommend using **four spaces** and no tabs, as this is a standard practice and will help a lot when collaborating with others.
 
 <a class="anchor" id="Getting-help"></a>
 ### Getting help
@@ -347,7 +372,7 @@ dir(d)
 ```
 
 
-> Note that google is often more helpful!
+> Note that google is often more helpful!  At least, as long as you find pages relating to the right version of python - we use python 3 for FSL, so check that what you find is appropriate for that.
 
 ---
 
@@ -365,7 +390,7 @@ print(e['a'])
 
 The keys and values can take on almost any type, even dictionaries!
 Python is nothing if not flexible.  However, each key must be unique
-and the dictionary must be "hashable".
+and [hashable](https://docs.python.org/3.5/glossary.html#term-hashable).
 
 <a class="anchor" id="Adding-to-a-dictionary"></a>
 ### Adding to a dictionary
@@ -394,7 +419,7 @@ Several variables can jointly work as loop variables in python, which is very co
 ```
 e = {'a' : 10, 'b': 20, 'c':555}
 for k, v in e.items():
-   print((k, v))
+    print((k, v))
 ```
 
 The print statement here constructs a tuple, which is often used in python.
@@ -407,7 +432,7 @@ for k in e:
 
 > Note that in both cases the order is arbitrary. The `sorted` function can be used if you want keys in a sorted order; e.g. `for k in sorted(e):` ...
 >
-> There are also other options if you want a dictionary with ordering.
+> There are also [other options](https://docs.python.org/3.5/library/collections.html#collections.OrderedDict) if you want a dictionary with ordering.
 
 ---
 
@@ -446,7 +471,7 @@ a[0] = 8888
 print(b)
 ```
 
-There is a constructor for each type and this con be useful for converting between types:
+There is a constructor for each type and this can be useful for converting between types:
 ```
 xt = (2, 5, 7)
 xl = list(xt)
@@ -460,20 +485,24 @@ print(xl)
 
 ```
 def foo1(x):
-   x.append(10)
+    x.append(10)
+    print('x: ', x)
 def foo2(x):
-   x = x + [10]
+    x = x + [10]
+    print('x: ', x)
 def foo3(x):
-   return x + [10]
+    print('return value: ', x + [10])
+    return x + [10]
 
 a = [5]
-print(a)
+print('a: ', a)
 foo1(a)
-print(a)
+print('a: ', a)
 foo2(a)
-print(a)
-foo3(a)
-print(a)
+print('a: ', a)
+b = foo3(a)
+print('a: ', a)
+print('b: ', b)
 ```
 
 > Note that we have defined some functions here - and the syntax
@@ -509,6 +538,10 @@ print('of' in 'a number of words')
 print(3 in [1, 2, 3, 4])
 ```
 
+
+A useful keyword is `None`, which is a bit like "null". This can be a default value for a variable and should be tested with the `is` operator rather than `==` (for technical reasons that it isn't worth going into here). For example: `a is None` or `a is not None` are the preferred tests.
+
+
 <a class="anchor" id="If-statements"></a>
 ### If statements
 
@@ -518,18 +551,18 @@ import random
 a = random.uniform(-1, 1)
 print(a)
 if a>0:
-   print('Positive')
+    print('Positive')
 elif a<0:
-   print('Negative')
+    print('Negative')
 else:
-   print('Zero')
+    print('Zero')
 ```
 
 Or more generally:
 ```
 a = []    # just one of many examples
 if not a:
-   print('Variable is true, or at least not empty')
+    print('Variable is true, or at least not empty')
 ```
 This can be useful for functions where a variety of possible input types are being dealt with. 
 
@@ -541,7 +574,7 @@ This can be useful for functions where a variety of possible input types are bei
 The `for` loop works like in bash:
 ```
 for x in [2, 'is', 'more', 'than', 1]:
-   print(x)
+    print(x)
 ```
 where a list or any other sequence (e.g. tuple) can be used.
 
@@ -565,7 +598,7 @@ alist = ['Some', 'set', 'of', 'items']
 blist = list(range(len(alist)))
 print(list(zip(alist, blist)))
 for x, y in zip(alist, blist):
-   print(y, x)
+    print(y, x)
 ```
 
 This type of loop can be used with any two lists (or similar) to iterate over them jointly.
@@ -579,15 +612,17 @@ import random
 n = 0
 x = 0
 while n<100:
-   x += random.uniform(0, 1)**2   # where ** is a power operation
-   if x>50:
-      break
-   n += 1
+    x += random.uniform(0, 1)**2   # where ** is a power operation
+    if x>50:
+        break
+    n += 1
 print(x)
 ```
 
 You can also use `continue` as in other languages.
 
+> Note that there is no `do ... while` construct.
+
 ---
 
 <a class="anchor" id="quick-intro"></a>
@@ -645,7 +680,7 @@ with we'll look at a simple function but note a few key points:
 def myfunc(x, y, z=0):
     r2 = x*x + y*y + z*z
     r = r2**0.5
-    return (r,  r2)
+    return r,  r2
 
 rad = myfunc(10, 20)
 print(rad)
@@ -657,17 +692,19 @@ print(rad)
 
 > Note that the `_` is used as shorthand here for a dummy variable
 > that you want to throw away.
+>
+> The return statement implicitly creates a tuple to return and is equivalent to `return (r, r2)`
 
 One nice feature of python functions is that you can name the
 arguments when you call them, rather than only doing it by position.
 For example:
 ```
 def myfunc(x, y, z=0, flag=''):
-   if flag=='L1':
-       r = abs(x) + abs(y) + abs(z)
-   else:
-       r = (x*x + y*y + z*z)**0.5
-   return r
+    if flag=='L1':
+        r = abs(x) + abs(y) + abs(z)
+    else:
+        r = (x*x + y*y + z*z)**0.5
+    return r
 
 rA = myfunc(10, 20)
 rB = myfunc(10, 20, flag='L1')
@@ -675,7 +712,7 @@ rC = myfunc(10, 20, flag='L1', z=30)
 print(rA, rB, rC)
 ```
 
-You will often see python functions called with these named arguments.
+You will often see python functions called with these named arguments. In fact, for functions with more than 2 or 3 variables this naming of arguments is recommended, because it clarifies what each of the arguments does for anyone reading the code.
 
 ---
 
@@ -687,7 +724,7 @@ that represent filenames and ID codes: e.g., `/vols/Data/pytreat/AAC, 165873, /v
 
 Write some code to do the following: 
  * separate out the filenames and ID codes into separate lists (ID's
- should be numerical values, not strings)
+ should be numerical values, not strings) - you may need several steps for this
  * loop over the two and generate a _string_ that could be used to
    rename the directories (e.g., `mv /vols/Data/pytreat/AAC /vols/Data/pytreat/S165873`) - we will cover how to actually execute these in a later practical
  * convert your dual lists into a dictionary, with ID as the key
@@ -699,6 +736,7 @@ Write some code to do the following:
 
 ```
 mstr = '/vols/Data/pytreat/AAC, 165873,  /vols/Data/pytreat/AAG,   170285, /vols/Data/pytreat/AAH, 196792, /vols/Data/pytreat/AAK, 212577, /vols/Data/pytreat/AAQ, 385376, /vols/Data/pytreat/AB, 444600, /vols/Data/pytreat/AC6, 454578, /vols/Data/pytreat/V8, 501502,   /vols/Data/pytreat/2YK, 667688, /vols/Data/pytreat/C3PO, 821971'
+
 ```
 
 
diff --git a/getting_started/05_nifti.md b/getting_started/05_nifti.md
index 9293ce18115c8dc186fdaef31c8ed300f20a749b..5e554469539e111084f5ae87aa29ad8c9f534316 100644
--- a/getting_started/05_nifti.md
+++ b/getting_started/05_nifti.md
@@ -117,7 +117,7 @@ If the voxel size of the image is different, then extra modifications will be re
 <a class="anchor" id="exercise"></a>
 ## Exercise
 
-Write some code to read in a 4D fMRI image (you can find one [here] if
+Write some code to read in a 4D fMRI image (you can find one [here](http://www.fmrib.ox.ac.uk/~mark/files/av.nii.gz) if
 you don't have one handy), calculate the tSNR and then save the 3D result.
 
 ```
diff --git a/getting_started/08_scripts.ipynb b/getting_started/08_scripts.ipynb
index b4e816dbd9fa12d733bdf1578684acf2538d2ac4..16faa7ec08486151715108408828cb714ff3908a 100644
--- a/getting_started/08_scripts.ipynb
+++ b/getting_started/08_scripts.ipynb
@@ -275,7 +275,25 @@
    ]
   }
  ],
- "metadata": {},
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  },
+  "language_info": {
+   "codemirror_mode": {
+    "name": "ipython",
+    "version": 3
+   },
+   "file_extension": ".py",
+   "mimetype": "text/x-python",
+   "name": "python",
+   "nbconvert_exporter": "python",
+   "pygments_lexer": "ipython3",
+   "version": "3.5.2"
+  }
+ },
  "nbformat": 4,
  "nbformat_minor": 2
 }