From 236b8b01d5df51dd246a2c543968a92d416fc698 Mon Sep 17 00:00:00 2001
From: "J.F.J. Laros" <jlaros@obscured.morspoort.fixedpoint.nl>
Date: Thu, 8 Aug 2013 18:47:45 +0200
Subject: [PATCH] Some more modifications on the classes slides.

---
 classes.ipynb | 450 +++++++++++++++++++++++++++++++++-----------------
 person.py     |  29 ++++
 2 files changed, 327 insertions(+), 152 deletions(-)
 create mode 100644 person.py

diff --git a/classes.ipynb b/classes.ipynb
index 5ea4e0d..71aaf87 100644
--- a/classes.ipynb
+++ b/classes.ipynb
@@ -27,6 +27,22 @@
       "License: [Creative Commons Attribution 3.0 License (CC-by)](http://creativecommons.org/licenses/by/3.0)"
      ]
     },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "%%html\n",
+      "<style type=\"text/css\">\n",
+      "/* Remove the vertical scrollbar added by nbconvert. */\n",
+      ".reveal {\n",
+      "  overflow-y: hidden;\n",
+      "}\n",
+      "</style>"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": []
+    },
     {
      "cell_type": "markdown",
      "metadata": {
@@ -52,6 +68,7 @@
      "collapsed": false,
      "input": [
       "from IPython.display import HTML, Image, IFrame\n",
+      "from person import Person\n",
       "%pylab inline"
      ],
      "language": "python",
@@ -69,7 +86,7 @@
        ]
       }
      ],
-     "prompt_number": 128
+     "prompt_number": 1
     },
     {
      "cell_type": "markdown",
@@ -79,9 +96,11 @@
       }
      },
      "source": [
-      "Imagine we are collecting a number of attributes of some persons:\n",
+      "Keeping track of attributes\n",
+      "===\n",
+      "\n",
+      "Suppose we want to keep track of some properties in a population:\n",
       "\n",
-      "* Eye colour.\n",
       "* Hair colour.\n",
       "* Weight.\n",
       "* Length."
@@ -95,6 +114,9 @@
       }
      },
      "source": [
+      "Non-object oriented\n",
+      "===\n",
+      "\n",
       "Should we use simple lists?"
      ]
     },
@@ -102,12 +124,11 @@
      "cell_type": "code",
      "collapsed": false,
      "input": [
-      "eye_colour = ['blue', 'blue', 'grey', 'green', 'brown']\n",
       "hair_colour = ['black', 'red', 'white', 'blue', 'red']\n",
       "weight = [80, 75, 130, 90, 64]\n",
       "length = [180, 174, 230, 161, 149]\n",
       "\n",
-      "eye_colour[3], hair_colour[3], weight[3], length[3]"
+      "hair_colour[3], weight[3], length[3]"
      ],
      "language": "python",
      "metadata": {},
@@ -115,13 +136,20 @@
       {
        "metadata": {},
        "output_type": "pyout",
-       "prompt_number": 129,
+       "prompt_number": 2,
        "text": [
-        "('green', 'blue', 90, 161)"
+        "('blue', 90, 161)"
        ]
       }
      ],
-     "prompt_number": 129
+     "prompt_number": 2
+    },
+    {
+     "cell_type": "markdown",
+     "metadata": {},
+     "source": [
+      "Getting all attributes is a bit of a hastle."
+     ]
     },
     {
      "cell_type": "code",
@@ -135,22 +163,32 @@
       {
        "metadata": {},
        "output_type": "pyout",
-       "prompt_number": 130,
+       "prompt_number": 3,
        "text": [
         "90"
        ]
       }
      ],
-     "prompt_number": 130
+     "prompt_number": 3
+    },
+    {
+     "cell_type": "markdown",
+     "metadata": {},
+     "source": [
+      "Getting one attribute is easy though."
+     ]
     },
     {
      "cell_type": "markdown",
      "metadata": {
       "slideshow": {
-       "slide_type": "slide"
+       "slide_type": "subslide"
       }
      },
      "source": [
+      "Non-object oriented\n",
+      "===\n",
+      "\n",
       "Or nested lists?"
      ]
     },
@@ -158,13 +196,13 @@
      "cell_type": "code",
      "collapsed": false,
      "input": [
-      "person = [['blue', 'black', 80, 180],\n",
-      "          ['blue', 'red', 75, 174],\n",
-      "          ['grey', 'white', 130, 230],\n",
-      "          ['green', 'blue', 90, 161],\n",
-      "          ['brown', 'red', 64, 149]]\n",
+      "persons = [['black', 80, 180],\n",
+      "          ['red', 75, 174],\n",
+      "          ['white', 130, 230],\n",
+      "          ['blue', 90, 161],\n",
+      "          ['red', 64, 149]]\n",
       "\n",
-      "person[3]"
+      "persons[3]"
      ],
      "language": "python",
      "metadata": {},
@@ -172,19 +210,26 @@
       {
        "metadata": {},
        "output_type": "pyout",
-       "prompt_number": 131,
+       "prompt_number": 4,
        "text": [
-        "['green', 'blue', 90, 161]"
+        "['blue', 90, 161]"
        ]
       }
      ],
-     "prompt_number": 131
+     "prompt_number": 4
+    },
+    {
+     "cell_type": "markdown",
+     "metadata": {},
+     "source": [
+      "Now all attributes are nicely grouped."
+     ]
     },
     {
      "cell_type": "code",
      "collapsed": false,
      "input": [
-      "person[3][2]"
+      "persons[3][2]"
      ],
      "language": "python",
      "metadata": {},
@@ -192,22 +237,32 @@
       {
        "metadata": {},
        "output_type": "pyout",
-       "prompt_number": 132,
+       "prompt_number": 5,
        "text": [
-        "90"
+        "161"
        ]
       }
      ],
-     "prompt_number": 132
+     "prompt_number": 5
+    },
+    {
+     "cell_type": "markdown",
+     "metadata": {},
+     "source": [
+      "Accessing a single attribute is a bit cryptic though."
+     ]
     },
     {
      "cell_type": "markdown",
      "metadata": {
       "slideshow": {
-       "slide_type": "slide"
+       "slide_type": "subslide"
       }
      },
      "source": [
+      "Non-object oriented\n",
+      "===\n",
+      "\n",
       "Or a list of dictionaries?"
      ]
     },
@@ -215,13 +270,13 @@
      "cell_type": "code",
      "collapsed": false,
      "input": [
-      "person = [{'eye_colour': 'blue', 'hair_colour': 'black', 'weight': 80, 'length': 180},\n",
-      "          {'eye_colour': 'blue', 'hair_colour': 'red', 'weight': 75, 'length': 174},\n",
-      "          {'eye_colour': 'grey', 'hair_colour': 'white', 'weight': 130, 'length': 230},\n",
-      "          {'eye_colour': 'green', 'hair_colour': 'blue', 'weight': 90, 'length': 161},\n",
-      "          {'eye_colour': 'brown', 'hair_colour': 'red', 'weight': 64, 'length': 149}]\n",
+      "persons = [{'hair_colour': 'black', 'weight': 80, 'length': 180},\n",
+      "          {'hair_colour': 'red', 'weight': 75, 'length': 174},\n",
+      "          {'hair_colour': 'white', 'weight': 130, 'length': 230},\n",
+      "          {'hair_colour': 'blue', 'weight': 90, 'length': 161},\n",
+      "          {'hair_colour': 'red', 'weight': 64, 'length': 149}]\n",
       "\n",
-      "person[3]"
+      "persons[3]"
      ],
      "language": "python",
      "metadata": {},
@@ -229,19 +284,19 @@
       {
        "metadata": {},
        "output_type": "pyout",
-       "prompt_number": 133,
+       "prompt_number": 6,
        "text": [
-        "{'eye_colour': 'green', 'hair_colour': 'blue', 'length': 161, 'weight': 90}"
+        "{'hair_colour': 'blue', 'length': 161, 'weight': 90}"
        ]
       }
      ],
-     "prompt_number": 133
+     "prompt_number": 6
     },
     {
      "cell_type": "code",
      "collapsed": false,
      "input": [
-      "person[3]['weight']"
+      "persons[3]['weight']"
      ],
      "language": "python",
      "metadata": {},
@@ -249,13 +304,13 @@
       {
        "metadata": {},
        "output_type": "pyout",
-       "prompt_number": 134,
+       "prompt_number": 7,
        "text": [
         "90"
        ]
       }
      ],
-     "prompt_number": 134
+     "prompt_number": 7
     },
     {
      "cell_type": "markdown",
@@ -265,68 +320,22 @@
       }
      },
      "source": [
-      "Object Oriented Programming\n",
+      "Classes\n",
       "===\n",
       "\n",
       "A class as a simple container:"
      ]
     },
-    {
-     "cell_type": "code",
-     "collapsed": false,
-     "input": [
-      "class Person(object):\n",
-      "    weight = 80\n",
-      "    \n",
-      "    def __init__(self, eye_colour='unknown', hair_colour='unknown', weight=0, length=0):\n",
-      "        self.eye_colour = eye_colour\n",
-      "        self.hair_colour = hair_colour\n",
-      "        if weight:\n",
-      "            self.weight = weight\n",
-      "        self.length = length\n",
-      "        \n",
-      "    def __str__(self):\n",
-      "        return \"Eye colour: {0}, Hair colour: {1}, Weight: {2}, Length: {3}\".format(\n",
-      "            self.eye_colour, self.hair_colour, self.weight, self.length)\n",
-      "    \n",
-      "    def __len__(self):\n",
-      "        return self.length\n",
-      "\n",
-      "    def feed(self, amount=3):\n",
-      "        self.weight += amount\n",
-      "        \n",
-      "    def bleach(self):\n",
-      "        self.hair_colour = 'white'\n",
-      "        \n",
-      "    def _convert_weight(self, multiplier):\n",
-      "        return self.weight * multiplier\n",
-      "        \n",
-      "    def weight_in_pounds(self):\n",
-      "        return self._convert_weight(2.20462)\n",
-      "        \n",
-      "    def weight_in_grams(self):\n",
-      "        return self._convert_weight(1000)"
-     ],
-     "language": "python",
-     "metadata": {
-      "slideshow": {
-       "slide_type": "skip"
-      }
-     },
-     "outputs": [],
-     "prompt_number": 135
-    },
     {
      "cell_type": "markdown",
      "metadata": {
       "slideshow": {
-       "slide_type": "slide"
+       "slide_type": "-"
       }
      },
      "source": [
       "    class Person(object):\n",
-      "        def __init__(self, eye_colour='unknown', hair_colour='unknown', weight=0, length=0):\n",
-      "            self.eye_colour = eye_colour\n",
+      "        def __init__(self, hair_colour='unknown', weight=0, length=0):\n",
       "            self.hair_colour = hair_colour\n",
       "            self.weight = weight\n",
       "            self.length = length"
@@ -336,7 +345,7 @@
      "cell_type": "code",
      "collapsed": false,
      "input": [
-      "someone = Person('green', 'blue', 90, 161)\n",
+      "someone = Person('blue', 90, 161)\n",
       "\n",
       "someone.weight"
      ],
@@ -346,39 +355,57 @@
       {
        "metadata": {},
        "output_type": "pyout",
-       "prompt_number": 136,
+       "prompt_number": 8,
        "text": [
         "90"
        ]
       }
      ],
-     "prompt_number": 136
+     "prompt_number": 8
+    },
+    {
+     "cell_type": "markdown",
+     "metadata": {
+      "slideshow": {
+       "slide_type": "subslide"
+      }
+     },
+     "source": [
+      "Classes\n",
+      "===\n",
+      "\n",
+      "Makes initialisation a lot easier."
+     ]
     },
     {
      "cell_type": "code",
      "collapsed": false,
      "input": [
-      "person = [Person(),\n",
-      "          Person('blue', 'red'),\n",
-      "          Person('grey', 'white', 130, 230),\n",
-      "          Person(weight=90),\n",
-      "          Person(weight=64, length=149)]\n",
+      "persons = [Person(),\n",
+      "           Person('red'),\n",
+      "           Person('white', 130, 230),\n",
+      "           Person(weight=90),\n",
+      "           Person(weight=64, length=149)]\n",
       "\n",
-      "person[3].weight"
+      "persons[3].weight"
      ],
      "language": "python",
-     "metadata": {},
+     "metadata": {
+      "slideshow": {
+       "slide_type": "-"
+      }
+     },
      "outputs": [
       {
        "metadata": {},
        "output_type": "pyout",
-       "prompt_number": 137,
+       "prompt_number": 9,
        "text": [
         "90"
        ]
       }
      ],
-     "prompt_number": 137
+     "prompt_number": 9
     },
     {
      "cell_type": "markdown",
@@ -387,11 +414,23 @@
        "slide_type": "slide"
       }
      },
+     "source": [
+      "Methods\n",
+      "==="
+     ]
+    },
+    {
+     "cell_type": "markdown",
+     "metadata": {
+      "slideshow": {
+       "slide_type": "-"
+      }
+     },
      "source": [
       "        class Person(object):\n",
       "            ...\n",
       "            \n",
-      "            def feed(self, amount=3):\n",
+      "            def eat(self, amount=3):\n",
       "                self.weight += amount\n",
       "            \n",
       "            def bleach(self):\n",
@@ -402,9 +441,9 @@
      "cell_type": "code",
      "collapsed": false,
      "input": [
-      "person = Person('green', 'blue', 90, 161)\n",
+      "someone = Person('blue', 90, 161)\n",
       "\n",
-      "person.weight, person.hair_colour"
+      "someone.weight, someone.hair_colour"
      ],
      "language": "python",
      "metadata": {},
@@ -412,21 +451,21 @@
       {
        "metadata": {},
        "output_type": "pyout",
-       "prompt_number": 138,
+       "prompt_number": 10,
        "text": [
         "(90, 'blue')"
        ]
       }
      ],
-     "prompt_number": 138
+     "prompt_number": 10
     },
     {
      "cell_type": "code",
      "collapsed": false,
      "input": [
-      "person.feed()\n",
-      "person.bleach()\n",
-      "person.weight, person.hair_colour"
+      "someone.eat()\n",
+      "someone.bleach()\n",
+      "someone.weight, someone.hair_colour"
      ],
      "language": "python",
      "metadata": {},
@@ -434,13 +473,13 @@
       {
        "metadata": {},
        "output_type": "pyout",
-       "prompt_number": 139,
+       "prompt_number": 11,
        "text": [
         "(93, 'white')"
        ]
       }
      ],
-     "prompt_number": 139
+     "prompt_number": 11
     },
     {
      "cell_type": "markdown",
@@ -449,6 +488,18 @@
        "slide_type": "slide"
       }
      },
+     "source": [
+      "Public and private methods\n",
+      "==="
+     ]
+    },
+    {
+     "cell_type": "markdown",
+     "metadata": {
+      "slideshow": {
+       "slide_type": "-"
+      }
+     },
      "source": [
       "    class Person(object):\n",
       "        ...\n",
@@ -463,11 +514,20 @@
       "            return self._convert_weight(1000)"
      ]
     },
+    {
+     "cell_type": "markdown",
+     "metadata": {},
+     "source": [
+      "Private methods are prefixed with an underscore.\n",
+      "\n",
+      "* Note that this is a convention, it is not enforced."
+     ]
+    },
     {
      "cell_type": "code",
      "collapsed": false,
      "input": [
-      "person.weight_in_pounds(), person.weight_in_grams()"
+      "someone.weight_in_pounds(), someone.weight_in_grams()"
      ],
      "language": "python",
      "metadata": {},
@@ -475,13 +535,13 @@
       {
        "metadata": {},
        "output_type": "pyout",
-       "prompt_number": 140,
+       "prompt_number": 12,
        "text": [
         "(205.02965999999998, 93000)"
        ]
       }
      ],
-     "prompt_number": 140
+     "prompt_number": 12
     },
     {
      "cell_type": "markdown",
@@ -490,23 +550,43 @@
        "slide_type": "slide"
       }
      },
+     "source": [
+      "Class variables vs. instance variables\n",
+      "==="
+     ]
+    },
+    {
+     "cell_type": "markdown",
+     "metadata": {
+      "slideshow": {
+       "slide_type": "-"
+      }
+     },
      "source": [
       "    class Person(object):\n",
-      "        weight = 80\n",
+      "        default_weight = 80\n",
       "        \n",
-      "        def __init__(self, eye_colour='unknown', hair_colour='unknown', weight=0, length=0):\n",
-      "            self.eye_colour = eye_colour\n",
+      "        def __init__(self, hair_colour='unknown', weight=0, length=0):\n",
       "            self.hair_colour = hair_colour\n",
-      "            if weight:\n",
-      "                self.weight = weight\n",
+      "            self.weight = weight or self.default_weight\n",
       "            self.length = length"
      ]
     },
+    {
+     "cell_type": "markdown",
+     "metadata": {},
+     "source": [
+      "Class variables are defined outside the methods.\n",
+      "\n",
+      "* It is still refererenced as **self.** inside the methods."
+     ]
+    },
     {
      "cell_type": "code",
      "collapsed": false,
      "input": [
       "someone = Person()\n",
+      "\n",
       "someone.weight"
      ],
      "language": "python",
@@ -515,13 +595,13 @@
       {
        "metadata": {},
        "output_type": "pyout",
-       "prompt_number": 142,
+       "prompt_number": 13,
        "text": [
         "80"
        ]
       }
      ],
-     "prompt_number": 142
+     "prompt_number": 13
     },
     {
      "cell_type": "code",
@@ -536,20 +616,21 @@
       {
        "metadata": {},
        "output_type": "pyout",
-       "prompt_number": 143,
+       "prompt_number": 14,
        "text": [
         "79"
        ]
       }
      ],
-     "prompt_number": 143
+     "prompt_number": 14
     },
     {
      "cell_type": "code",
      "collapsed": false,
      "input": [
-      "Person.weight = 90\n",
+      "Person.default_weight = 90\n",
       "someone = Person()\n",
+      "\n",
       "someone.weight"
      ],
      "language": "python",
@@ -558,13 +639,13 @@
       {
        "metadata": {},
        "output_type": "pyout",
-       "prompt_number": 144,
+       "prompt_number": 15,
        "text": [
         "90"
        ]
       }
      ],
-     "prompt_number": 144
+     "prompt_number": 15
     },
     {
      "cell_type": "markdown",
@@ -573,24 +654,55 @@
        "slide_type": "slide"
       }
      },
+     "source": [
+      "Special methods\n",
+      "==="
+     ]
+    },
+    {
+     "cell_type": "markdown",
+     "metadata": {},
+     "source": [
+      "    print someone\n",
+      "    <__main__.Person instance at 0x321ebd8>"
+     ]
+    },
+    {
+     "cell_type": "markdown",
+     "metadata": {
+      "slideshow": {
+       "slide_type": "-"
+      }
+     },
      "source": [
       "    class Person(object):\n",
       "        ...\n",
       "    \n",
       "        def __str__(self):\n",
-      "            return \"Eye colour: {0}, Hair colour: {1}, Weight: {2}, Length: {3}\".format(\n",
-      "                self.eye_colour, self.hair_colour, self.weight, self.length)\n",
+      "            return \"Person with hair colour: {0}, weight: {1} and length: {2}\".format(\n",
+      "                self.hair_colour, self.weight, self.length)\n",
       "     \n",
       "        def __len__(self):\n",
       "            return self.length"
      ]
     },
+    {
+     "cell_type": "markdown",
+     "metadata": {},
+     "source": [
+      "Special methods are prefixed and suffixed with double underscores.\n",
+      "\n",
+      "* There are methods for adding (**\\_\\_add\\_\\_**), subtracting (**\\_\\_sub\\_\\_**), etc."
+     ]
+    },
     {
      "cell_type": "code",
      "collapsed": false,
      "input": [
-      "print person\n",
-      "len(person)"
+      "someone = Person('blue', 90, 161)\n",
+      "\n",
+      "print someone\n",
+      "len(someone)"
      ],
      "language": "python",
      "metadata": {},
@@ -599,19 +711,31 @@
        "output_type": "stream",
        "stream": "stdout",
        "text": [
-        "Eye colour: green, Hair colour: white, Weight: 93, Length: 161\n"
+        "Person with hair colour: blue, weight: 90 and length: 161\n"
        ]
       },
       {
        "metadata": {},
        "output_type": "pyout",
-       "prompt_number": 126,
+       "prompt_number": 16,
        "text": [
         "161"
        ]
       }
      ],
-     "prompt_number": 126
+     "prompt_number": 16
+    },
+    {
+     "cell_type": "markdown",
+     "metadata": {
+      "slideshow": {
+       "slide_type": "slide"
+      }
+     },
+     "source": [
+      "Class inheritance\n",
+      "==="
+     ]
     },
     {
      "cell_type": "code",
@@ -619,23 +743,30 @@
      "input": [
       "class DutchPerson(Person):\n",
       "    def __str__(self):\n",
-      "        return \"Oogkleur: {0}, Haarkleur: {1}, Gewicht: {2}, Lengte: {3}\".format(\n",
-      "            self.eye_colour, self.hair_colour, self.weight, self.length)"
+      "        return \"Persoon met haarkleur: {0}, gewicht: {1} en lengte: {2}\".format(\n",
+      "            self.hair_colour, self.weight, self.length)"
      ],
      "language": "python",
      "metadata": {
       "slideshow": {
-       "slide_type": "slide"
+       "slide_type": "-"
       }
      },
      "outputs": [],
-     "prompt_number": 127
+     "prompt_number": 17
+    },
+    {
+     "cell_type": "markdown",
+     "metadata": {},
+     "source": [
+      "A subclass can have added functionality, or it can override some functionality."
+     ]
     },
     {
      "cell_type": "code",
      "collapsed": false,
      "input": [
-      "sinterklaas = DutchPerson('blue', 'white', 85, 191)\n",
+      "sinterklaas = DutchPerson('white', 85, 191)\n",
       "\n",
       "print sinterklaas"
      ],
@@ -646,11 +777,23 @@
        "output_type": "stream",
        "stream": "stdout",
        "text": [
-        "Oogkleur: blue, Haarkleur: white, Gewicht: 85, Lengte: 191\n"
+        "Persoon met haarkleur: white, gewicht: 85 en lengte: 191\n"
        ]
       }
      ],
-     "prompt_number": 86
+     "prompt_number": 18
+    },
+    {
+     "cell_type": "markdown",
+     "metadata": {
+      "slideshow": {
+       "slide_type": "slide"
+      }
+     },
+     "source": [
+      "An object oriented solution for the Sequencer assignment.\n",
+      "==="
+     ]
     },
     {
      "cell_type": "code",
@@ -658,14 +801,14 @@
      "input": [
       "class Read(object):\n",
       "    def __init__(self):\n",
-      "        self.read = \"\"\n",
+      "        self.read = []\n",
       "        self.qual = []\n",
       "            \n",
       "    def __str__(self):\n",
-      "        return self.read\n",
+      "        return \"\".join(self.read)\n",
       "        \n",
-      "    def add(self, base):\n",
-      "        self.read += base[0]\n",
+      "    def append(self, base):\n",
+      "        self.read.append(base[0])\n",
       "        self.qual.append(base[1])\n",
       "            \n",
       "    def quality(self):\n",
@@ -674,16 +817,18 @@
       "    def trim(self, score):\n",
       "        for position in range(len(self.read) - 1, -1, -1):\n",
       "            if self.qual[position] >= score:\n",
-      "                return self.read[:position]"
+      "                self.read = self.read[:position]\n",
+      "                self.qual = self.qual[:position]\n",
+      "                break"
      ],
      "language": "python",
      "metadata": {
       "slideshow": {
-       "slide_type": "slide"
+       "slide_type": "-"
       }
      },
      "outputs": [],
-     "prompt_number": 7
+     "prompt_number": 19
     },
     {
      "cell_type": "code",
@@ -697,16 +842,17 @@
       "reads = [Read() for _ in range(spots)]\n",
       "for tile in run:\n",
       "    for read_id, base in enumerate(tile):\n",
-      "        reads[read_id].add(base)\n",
+      "        reads[read_id].append(base)\n",
       "\n",
       "for i in reads:\n",
       "    print i, i.quality()\n",
-      "    print i.trim(39)"
+      "    i.trim(39)\n",
+      "    print i, i.quality()"
      ],
      "language": "python",
      "metadata": {
       "slideshow": {
-       "slide_type": "slide"
+       "slide_type": "subslide"
       }
      },
      "outputs": [
@@ -714,14 +860,14 @@
        "output_type": "stream",
        "stream": "stdout",
        "text": [
-        "GGTGTGATTCCCGTTCGGTGGGCCGCCTTGGGTCATTGCTCGGTTGAGGAGGGAAGACCT 30\n",
-        "GGTGTGATTCCCGTTCGGTGGGCCGCCTTGGGTCAT\n",
-        "GGCTTTAGAATGTCTCCTGCATCTGATGCTATTAAAAGCTATGTTTTTCACATAGTACGG 29\n",
-        "GGCTTTAGAATGTCTCCTGCATCTGATGCTATTAAAAGCTATGTTTTTCACATAGT\n"
+        "ATCATTAATTCTAAGTAGTCACACCGGATTAACGATCCCTCTTAGCCAACGCTTTTAGTC 29\n",
+        "ATCATTAATTCTAAGTAGTCACACCGGATTAACGATCCCTCTTAGCCAACGCTTT 30\n",
+        "TCCACTAGTGGGAATACTTAGTATTACACGGACATAGTTTACTCCCATTATATGCTAGAA 27\n",
+        "TCCACTAGTGGGAATACT 36\n"
        ]
       }
      ],
-     "prompt_number": 8
+     "prompt_number": 20
     }
    ],
    "metadata": {}
diff --git a/person.py b/person.py
new file mode 100644
index 0000000..857cc10
--- /dev/null
+++ b/person.py
@@ -0,0 +1,29 @@
+class Person(object):
+    default_weight = 80
+
+    def __init__(self, hair_colour='unknown', weight=0, length=0):
+        self.hair_colour = hair_colour
+        self.weight = weight or self.default_weight
+        self.length = length
+
+    def __str__(self):
+        return "Person with hair colour: {0}, weight: {1} and length: {2}".format(
+            self.hair_colour, self.weight, self.length)
+
+    def __len__(self):
+        return self.length
+
+    def eat(self, amount=3):
+        self.weight += amount
+
+    def bleach(self):
+        self.hair_colour = 'white'
+
+    def _convert_weight(self, multiplier):
+        return self.weight * multiplier
+
+    def weight_in_pounds(self):
+        return self._convert_weight(2.20462)
+
+    def weight_in_grams(self):
+        return self._convert_weight(1000)
-- 
GitLab