{ "metadata": { "name": "", "signature": "sha256:728ee11eec179e20d21f862d9084e91ff1a4dfa62d5b5fafddf331aaf52a8a78" }, "nbformat": 3, "nbformat_minor": 0, "worksheets": [ { "cells": [ { "cell_type": "heading", "level": 1, "metadata": {}, "source": [ "Hands-on: Python Fundamentals -- Basic Containers: Lists" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Objectives:**\n", "\n", "Upon completion of this lesson, you should be able to:\n", "\n", "* Describe the characteristics of the list in Python\n", "\n", "* Perform basic operations with lists including creation, concatenation, repetition, slicing, and traversing" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "There are Four basic containers in Python: list, tuple, set and dictionary. We will first consider possibly the \"simplest\" one -- **list**." ] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "The list data structure" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* In Python, a list is a mutable sequence of values. Mutable means that we can change separate entries within a list\n", "\n", "\n", "* Each value in the list is an element or item\n", "\n", "\n", "* Elements can be any Python data type\n", "\n", "\n", "* Lists can mix data types\n", "\n", "\n", "* Elements can be nested lists" ] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Creating lists" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "\n", "* \n", "Lists are created with comma-separated values inside brackets." ] }, { "cell_type": "code", "collapsed": false, "input": [ "numbers = [1, 2, 3, 4]\n", "print numbers\n", "cheeses = ['swiss', 'cheddar',\n", " 'ricotta', 'gouda']\n", "print cheeses" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Creating lists" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "\n", "* \n", "You can mix types" ] }, { "cell_type": "code", "collapsed": false, "input": [ "mixed = [1, 'a', 3.45]\n", "print mixed" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "\n", "* \n", "and lists with single items (or no items) are lists" ] }, { "cell_type": "code", "collapsed": false, "input": [ "single = ['z']\n", "print single, type(single)\n", "empty = []\n", "print empty" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* you can create a list for any *iterable* ( by simply passing it to the **list()** function" ] }, { "cell_type": "code", "collapsed": false, "input": [ "print list(\"I am a string\")" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "and more often you will see the use of `str.split()` method to create list of separate \"words\":" ] }, { "cell_type": "code", "collapsed": false, "input": [ "print \"I am a string\".split()" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "heading", "level": 3, "metadata": {}, "source": [ "Read lines from a file" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In Python it is very easy to read external files. Even though we haven't covered that yet, here is a little taster, which reads first 10 lines from a file in the parent directory:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "with open(\"../README.md\") as f:\n", " print f.readlines()[:10]" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- - -\n", "**Excercise**\n", "\n", "Improve upon that snippet above, to print only the lines a hash (\"#\") (you might like to use `str.startwith()`, `str.lstrip()`, `str.rstrip()` functions)\n", "\n", "\n", "*Hints*: list is \"iterable\" so recall how we loop conveniently through an iterable with a **for** loop\n", "\n", "**Extra credit**\n", "\n", "Enhance to print only the lines which come from the \"Code of conduct\" sub-section" ] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Repeating a list" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* Use the * operator to expand a list via repeatition:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "meat = ['spam']*4\n", "print meat\n", "print [1, 2, 3]*3" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- - -\n", "**Microquiz**\n", "\n", "With what other basic type * operator resulted in a very similar behavior?" ] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "List indexing" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* Elements within a list are indexed (**starting with 0**)" ] }, { "cell_type": "code", "collapsed": false, "input": [ "print cheeses[0]" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- - -\n", "**Microquiz**\n", "\n", "Why do you think indexing in generic programming languages (C, C++, ...) as a rule starts with 0?" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "\n", "* \n", "Lists are \n", "*mutable*" ] }, { "cell_type": "code", "collapsed": false, "input": [ "cheeses[0] = 'Feta'\n", "print cheeses" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- - -\n", "**Microquiz/Excercise**\n", "\n", "Are strings *mutable*?" ] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Slicing a list" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "\n", "* \n", "Like strings and other sequences, lists can be \n", "*sliced*.\n", "\n", "\n", "* \n", "**Slicing syntax**: \n", "`l[start:stop:stride]`\n", "\n", "\n", "\n", "All slicing parameters are optional:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "l = range(1, 6)\n", "print(l)" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "print(l[3:])" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "l[:3]" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "l[::2]" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- - -\n", "**Note that**\n", "\n", "* `l[start:stop]` contains the elements with indices `i` such as `start <= i < stop` (`i` ranging from `start` to `stop-1`), i.e. includes `start` but does not includes `stop`\n", "\n", "\n", "* Thererore, `l[start:stop]` has `(stop-start)` elements." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- - -\n", "**Excercise #1**\n", "\n", "`stride` can be negative. Explore on the above example effects -- what does having negative `stride` result in?" ] }, { "cell_type": "code", "collapsed": false, "input": [], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- - -\n", "**Excercise #2**\n", "\n", "`stop` can also be negative. Explore on the above example effects -- what does having negative `stop` result in?" ] }, { "cell_type": "code", "collapsed": false, "input": [], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Changing a slice" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "\n", "* \n", "You can use slices to modify the contents of a list:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "roster = ['Meghan', 'Tricia', 'Juan',\n", " 'Alton', 'Darrel', 'Jen']\n", "print roster\n", "roster[1:3] = ['Sam', 'Kerri'] # Assign multiple entries at once\n", "print roster\n", "roster[3:5] = ['Tayla'] # Assigning less than selected results in \"shrinking\" of the list\n", "print roster" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Inserting elements" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "\n", "* \n", "Slice notation" ] }, { "cell_type": "code", "collapsed": false, "input": [ "roster[2:2] = ['Dana', 'Ryan']\n", "print roster" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Deleting elements" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "\n", "* \n", "Setting a slice to empty list will delete those elements:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "roster[3:5] = []\n", "print roster" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "\n", "* \n", "Or you can use the del keyword:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "del roster[2:3]\n", "print roster" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "The insert method" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "\n", "* \n", "Lists have an `insert` method:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "roster.insert?" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "\n", "* \n", "Let's see it in action:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "roster.insert(2, 'Jakob')\n", "print roster" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "The append and extend methods" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "\n", "* \n", "The `append` method adds individual items to a list:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "roster.append('Tonya')\n", "print roster" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "\n", "* \n", "The `extend` method adds a list to the end of an existing list:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "adds = ['Ian', 'Stacie']\n", "roster.extend(adds)\n", "print roster" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- - -\n", "**Microquiz**\n", "\n", "- Should you .append or .extend a list with 123?" ] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Extending a list with operators" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "\n", "* \n", "Can also use += operator" ] }, { "cell_type": "code", "collapsed": false, "input": [ "roster += ['Anya']\n", "print roster" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "\n", "* \n", "Or simply the + operator" ] }, { "cell_type": "code", "collapsed": false, "input": [ "a = [1, 2, 3]\n", "b = [4, 5, 6]\n", "c = a + b\n", "print a, b, c" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "\n", "* \n", "The + operator returns a new list that is a concatenation of two lists" ] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "List assignment and aliasing" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "\n", "* \n", "The slice operator returns a copy of a list" ] }, { "cell_type": "code", "collapsed": false, "input": [ "a = [1, 2, 3, 4]\n", "b = a\n", "c = a[:]\n", "a[2] = 9\n", "print a, b, c" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Traversing a list" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* There are many ways to **loop** over a list, and such functions as **enumerate**, **zip** and others could be of great help:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "for index in range(len(roster)):\n", " print roster[index]" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "for student in roster:\n", " print student" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "for index, student in enumerate(roster):\n", " print index, student " ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Note** how `enumerate` keeps track of the index and the item, which can come in handy -- you don't really need to use ```for i in range(len(l))``` to traverse the list" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- - -\n", "**Microquiz**\n", "\n", "* What does this do?\n", "\n", "```python\n", "empty = []\n", "for x in empty:\n", " print(x)\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- - -\n", "**Excercise**\n", "\n", "I have mentioned above **zip** function which I promised would help to make the world a better place. So -- use learnt knowedge to figure out what it does and come up with a usecase/example for its usage." ] }, { "cell_type": "code", "collapsed": false, "input": [], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Nested lists" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "\n", "* \n", "You can nest lists of lists of lists..." ] }, { "cell_type": "code", "collapsed": false, "input": [ "nested = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]\n", "print nested\n", "print nested[0]\n", "print nested[0][1]" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Traversing nested lists" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* Each nested list can be traversed in the same way as an individual list:\n", "\n", "* By index (less efficient, often ugly):" ] }, { "cell_type": "code", "collapsed": false, "input": [ "for i in range(len(nested)):\n", " for j in range(len(nested[i])):\n", " print nested[i][j]" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* Or item (faster, reads better)" ] }, { "cell_type": "code", "collapsed": false, "input": [ "for nest in nested:\n", " for item in nest:\n", " print item" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Using lists: cumulate.py" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* You can pass lists as arguments to functions:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "def cumulate(seq):\n", " c_sum = 0\n", " for item in seq:\n", " c_sum += item\n", " return c_sum\n", "\n", "a = [12, 78, 32, 82]\n", "s = cumulate(a)\n", "print s" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Returning lists from functions" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "\n", "* \n", "You can return lists from functions:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "def only_upper(t):\n", " res = []\n", " for s in t:\n", " if s.isupper():\n", " res.append(s)\n", " return res\n", "\n", "text = 'Bold cOlOrs Make for Easy Reading'\n", "secret = only_upper(text)\n", "print secret" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Modifying lists in functions" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* In Python, arguments are passed by reference\n", "\n", "\n", "* The parameter in the function is an alias for the argument that was passed in\n", "\n", "\n", "* **If a mutable object is changed inside the function, it is also changed outside the function!**" ] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Example: byref.py" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "\n", "* \n", "Here we illustrate modifying a list in a function:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "def change(seq):\n", " print 'Passed in: ' + str(seq)\n", " seq.append('new item')\n", " print 'Changed to: ' + str(seq)\n", "\n", "original = [1, 2, 3]\n", "print original\n", "change(original)\n", "print original" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Example: byref2.py" ] }, { "cell_type": "code", "collapsed": false, "input": [ "def change(seq):\n", " print 'Passed in: ' + str(seq)\n", " seq.append('new item')\n", " print 'Changed to: ' + str(seq)\n", " new_seq = ['created', 'in', 'function']\n", " print 'New seq: ' + str(new_seq)\n", "\n", "original = [1, 2, 3]\n", "new_seq = ['outside','the','function']\n", "print original\n", "change(original)\n", "print original\n", "print new_seq" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "WARNING: Do not use [] list as default keyword argument" ] }, { "cell_type": "code", "collapsed": false, "input": [ "def change(seq=[]):\n", " seq.append(1)\n", " return seq\n", "\n", "original = [1, 2, 3]\n", "for i in range(4):\n", " print change()" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Instead define default to None and assign within the function, thus a new list would be created on each call:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "def change(seq=None):\n", " seq = seq or []\n", " seq.append(1)\n", " return seq\n", "\n", "original = [1, 2, 3]\n", "for i in range(4):\n", " print change()" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "List comprehensions" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "*Very* powerful technique allowing for efficient construction of new lists.\n", "\n", "It is usually prefered over *loop*ing regularly to fill up pre-created list. Compare:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "l = []\n", "for s in \"something creative\":\n", " l.append(s)" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "to" ] }, { "cell_type": "code", "collapsed": false, "input": [ "l = [s for s in \"something creative\"]\n", "print(l)" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- - -\n", "\n", "**Miniquiz**\n", "\n", "well -- above example is boring, since we could accomplish the same by ...?" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We could store multiple values per each item right away:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "l = [(i, s, len(s)) for i, s in enumerate(\"something creative\")]\n", "print(l)" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "heading", "level": 3, "metadata": {}, "source": [ "Conditionals in the comprehensions" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* List comprehension allows to specify a condition if a given item should be included in the resultant list:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "print [s for s in \"something creative\" if s in \"eai\"]" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- - -\n", "**Excercise**\n", "\n", "Recall the example above for reading section headings from README.md. Create a list comprehension which would create a list of line headings." ] }, { "cell_type": "heading", "level": 3, "metadata": {}, "source": [ "WARNING: variables defined in list comprehensions are local to the entire code block" ] }, { "cell_type": "code", "collapsed": false, "input": [ "[x for x in \"123\"]\n", "print x" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "and they would override values defined locally before:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "i = \"precious\"\n", "print i\n", "[i for i in [\"evil\"]]\n", "print i" ], "language": "python", "metadata": {}, "outputs": [] } ], "metadata": {} } ] }