<commit_before>{
 "metadata": {
  "name": ""
 },
 "nbformat": 3,
 "nbformat_minor": 0,
 "worksheets": [
  {
   "cells": [
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "Source notebook for lesson \u201cTuples\u201d. Source located in `nbsource/tuples.ipynb`. Created automatically by sanity on 2014-03-05 at 04:03:51.874552."
     ]
    }
   ],
   "metadata": {}
  }
 ]
}<commit_msg>Finish off tuple content with over the top named tuple stuff.<commit_after>{
 "metadata": {
  "name": ""
 },
 "nbformat": 3,
 "nbformat_minor": 0,
 "worksheets": [
  {
   "cells": [
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "Source notebook for lesson \u201cTuples\u201d. Source located in `nbsource/tuples.ipynb`. Created automatically by sanity on 2014-03-05 at 04:03:51.874552."
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "The tuple is a sequence container not unlike the list except that once created you cannot change it. You might wonder why such a container even exists, and the real answer is that it is designed principally for holding sequences of values where the _position_ of an item has significance.\n",
      "\n",
      "For example, [the `os.stat()` library function call](http://docs.python.org/2/library/os.html#os.stat \"\") used to return a tuple of nine elements: if `s` is the output of an `os.stat()` call on a specific path then `s[8]` is the creation time of that path and `s[7]` is its modification time."
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "It is often more convenient to refer to the elements of a returned tuple using attribute names, and can certainly improve a program's readability immensely. For that reason nowadays `os.stat()` returns a __[`collections.namedtuple`](http://docs.python.org/2/library/collections.html#collections.namedtuple \"\")__ object."
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "To avoid causing failures in existing code you can also use the standard tuple access mechanisms. Nevertheless tuples are firmly embedded in Python, and they do allow you to create a structure that you can pass to someone else's code with a reasonable expectation it won't be mangled. Like strings, tuples are an _immutable_ type - once created they can't be changed."
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "Tuples are represented in Python source code as a sequence of values separated by commas."
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "xy_position = 25, 50"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [],
     "prompt_number": 1
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "xy_position"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "metadata": {},
       "output_type": "pyout",
       "prompt_number": 2,
       "text": [
        "(25, 50)"
       ]
      }
     ],
     "prompt_number": 2
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "As you can see, the interpreter puts parentheses around the list when it represents a tuple (you will probably remember that lists are represented in square brackets). It's conventional, but often not necessary, to write parentheses arund the tuples in your source. After all, that's just a parenthesized tuple. There are some situations, such as passing a tuple as an argument to a function, where the parentheses are required.\n",
      "\n",
      "As a sequence type the elements of a tuple can be accessed by numeric index just like the elements of a list or the characters of a string."
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "xy_position[0]"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "metadata": {},
       "output_type": "pyout",
       "prompt_number": 3,
       "text": [
        "25"
       ]
      }
     ],
     "prompt_number": 3
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "xy_position[1]"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "metadata": {},
       "output_type": "pyout",
       "prompt_number": 4,
       "text": [
        "50"
       ]
      }
     ],
     "prompt_number": 4
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "The tuple does not have as many methods as the list type. You can find things with the `index()` method and count them with `count()`."
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "heterogeneous = (1, \"potato\", 2, \"potato\", 3, \"potato\", 4)\n",
      "heterogeneous.index(3), heterogeneous.count(\"potato\")"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "metadata": {},
       "output_type": "pyout",
       "prompt_number": 8,
       "text": [
        "(4, 3)"
       ]
      }
     ],
     "prompt_number": 8
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "The expression on the last line is itself a tuple. The values in a tuple are not restricted to literal objects but can be full-blown Python expressions."
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "Here you see the response when an attempt is made to alter one of its values."
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "heterogeneous[3] = \"tomato\""
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "ename": "TypeError",
       "evalue": "'tuple' object does not support item assignment",
       "output_type": "pyerr",
       "traceback": [
        "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[0;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
        "\u001b[0;32m<ipython-input-9-4ba7e7c8eb2d>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mheterogeneous\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m3\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m\"tomato\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
        "\u001b[0;31mTypeError\u001b[0m: 'tuple' object does not support item assignment"
       ]
      }
     ],
     "prompt_number": 9
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "Please note that this does NOT mean that objects contained within the tuple cannot be mutated. In this next example we create a tuple one of whose elements is a list. You can see that the tuple is representd differently after the change to its element, but the change is allowed because the tuple element still refers to the same object."
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "immutable = (0, 1, 2, [3, 4, 5])\n",
      "print(immutable[3])\n",
      "immutable[3][1] = \"See - it can be done\"\n",
      "print(immutable[3], immutable)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "[3, 4, 5]\n",
        "[3, 'See - it can be done', 5] (0, 1, 2, [3, 'See - it can be done', 5])\n"
       ]
      }
     ],
     "prompt_number": 11
    },
    {
     "cell_type": "heading",
     "level": 4,
     "metadata": {},
     "source": [
      "A Note on the `namedtuple`"
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "Would you rather write (and how about reading?)\n",
      "\n",
      "    s = os.stat(some_path)\n",
      "    some_path_mod_time = s[7]\n",
      "\n",
      "when you could instead use the more modern\n",
      "\n",
      "    s = os.stat(some_path)\n",
      "    some_path_mod_time = s.st_mtime\n",
      "\n",
      "The mnemonic assistance of the name is incredibly valuable in keeping Python code (or indeed that of any programming language) readable."
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "A `namedtuple` is a type. You create a new type by calling `collections.namedtuple()` with two arguments. The first is a string naming the type (used when instances are represented, for example) and the second specifies the names of the attributes that each instance will have.\n",
      "\n",
      "The attribute names can be presented as either:\n",
      "\n",
      "* a list of strings, _e.g._ `['name', 'address', 'phone_number']`\n",
      "* a string containing whitespace-separated field names, _e.g._ `\"name address phone_number\"`, or\n",
      "* a string containing a comma-separated list of field names, _e.g._ `\"name, address, phone_number\"`\n",
      "\n",
      "This flexibility can avoid tiresome conversions in many cases."
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "from collections import namedtuple\n",
      "AddressBookEntry = namedtuple(\"AddressBookEntry\", \"name, address, phone_number\")\n",
      "steve = AddressBookEntry(\"<NAME>\", \"123 Neverland Road\", \"123 5555\")\n",
      "steve"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "metadata": {},
       "output_type": "pyout",
       "prompt_number": 13,
       "text": [
        "AddressBookEntry(name='<NAME>', address='123 Neverland Road', phone_number='123 5555')"
       ]
      }
     ],
     "prompt_number": 13
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "Once you create your named tuple definition it operates exactly the same as a built-in type."
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "type(int), type(AddressBookEntry), type(steve)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "metadata": {},
       "output_type": "pyout",
       "prompt_number": 20,
       "text": [
        "(builtins.type, builtins.type, __main__.AddressBookEntry)"
       ]
      }
     ],
     "prompt_number": 20
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "The first argument has to be a valid identifier."
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "_ = namedtuple(\"several words\", \"list of field names\")"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "ename": "ValueError",
       "evalue": "Type names and field names must be valid identifiers: 'several words'",
       "output_type": "pyerr",
       "traceback": [
        "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[0;31mValueError\u001b[0m                                Traceback (most recent call last)",
        "\u001b[0;32m<ipython-input-15-81e83821456c>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0m_\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mnamedtuple\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"several words\"\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m\"list of field names\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
        "\u001b[0;32m/Users/sholden/.virtualenvs/py3/lib/python3.3/collections/__init__.py\u001b[0m in \u001b[0;36mnamedtuple\u001b[0;34m(typename, field_names, verbose, rename)\u001b[0m\n\u001b[1;32m    336\u001b[0m         \u001b[0;32mif\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mname\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0misidentifier\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    337\u001b[0m             raise ValueError('Type names and field names must be valid '\n\u001b[0;32m--> 338\u001b[0;31m                              'identifiers: %r' % name)\n\u001b[0m\u001b[1;32m    339\u001b[0m         \u001b[0;32mif\u001b[0m \u001b[0m_iskeyword\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mname\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    340\u001b[0m             raise ValueError('Type names and field names cannot be a '\n",
        "\u001b[0;31mValueError\u001b[0m: Type names and field names must be valid identifiers: 'several words'"
       ]
      }
     ],
     "prompt_number": 15
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "When creating `namedtuple` instances you can just pass the attribute values in the same sequence as they were defined. This is easy, but prone to error if changes such as the ordering of the names in the definition takes place.\n",
      "\n",
      "It is therefore sound practice (though ignoring it is neither uncommon nor inexcusable) to use keyword arguments to the instantiation calls as shown here."
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "pat = AddressBookEntry(name=\"<NAME>\",\n",
      "                       phone_number=\"124 5555\",\n",
      "                       address=\"125 Neverland Road\")\n",
      "pat"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "metadata": {},
       "output_type": "pyout",
       "prompt_number": 22,
       "text": [
        "AddressBookEntry(name='<NAME>', address='125 Neverland Road', phone_number='124 5555')"
       ]
      }
     ],
     "prompt_number": 22
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "kirby = AddressBookEntry(address=\"121 Neverland Road\",\n",
      "                         phone_number=\"122 5555\",\n",
      "                         name=\"<NAME>\")\n",
      "kirby"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "metadata": {},
       "output_type": "pyout",
       "prompt_number": 23,
       "text": [
        "AddressBookEntry(name='<NAME>', address='121 Neverland Road', phone_number='122 5555')"
       ]
      }
     ],
     "prompt_number": 23
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "When you take these address book values you can treat them just like any other type, and use dotted notation for the individual attributes."
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "address_book = [kirby, pat, steve]\n",
      "for entry in address_book:\n",
      "    print(entry.name, entry.phone_number)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "<NAME> 122 5555\n",
        "<NAME> 124 5555\n",
        "<NAME> 123 5555\n"
       ]
      }
     ],
     "prompt_number": 26
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [],
     "language": "python",
     "metadata": {},
     "outputs": []
    }
   ],
   "metadata": {}
  }
 ]
}
{'fraction_non_alphanumeric': 0.1677791458751863, 'fraction_numerical': 0.052102909727172575, 'mean_word_length': 2.244743481917578, 'pattern_counts': {'":': 212, '<': 16, '<?xml version=': 0, '>': 19, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 1, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1182009', 'n_tokens_mistral': 5692, 'n_tokens_neox': 5146, 'n_words': 1309}