{ "cells": [ { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true, "deletable": true, "editable": true }, "outputs": [], "source": [ "from __future__ import print_function" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "# functions" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "Functions are used to organize program flow, especially to allow us to easily do commonly needed tasks over and over again. We've already used a lot of functions, such as those that work on lists (`append()` and `pop()`) or strings (like `replace()`). Here we see how to write our own functions" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "A function takes arguments, listed in the `()` and returns a value. Even if you don't explictly give a return value, one will be return (e.g., `None`). \n", "\n", "Here's a simple example of a function that takes a single argument, `i`" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "in the function, i = 10\n", "in the function, i = 5\n" ] } ], "source": [ "def my_fun(i):\n", " print(\"in the function, i = {}\".format(i))\n", " \n", "my_fun(10)\n", "my_fun(5)" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "in the function, i = 0\n", "None\n" ] } ], "source": [ "a = my_fun(0)\n", "print(a)" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "functions are one place where _scope_ comes into play. A function has its own _namespace_. If a variable is not defined in that function, then it will look to the namespace from where it was called to see if that variable exists there. \n", "\n", "However, you should avoid this as much as possible (variables that persist across namespaces are called global variables).\n", "\n", "We already saw one instance of namespaces when we imported from the `math` module." ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "-----\n", "----------\n" ] } ], "source": [ "global_var = 10\n", "\n", "def print_fun(string, n):\n", " if n < global_var:\n", " print(string*n)\n", " else:\n", " print(string*global_var)\n", "\n", "print_fun(\"-\", 5)\n", "print_fun(\"-\", 20)" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "collapsed": true, "deletable": true, "editable": true }, "outputs": [], "source": [ "global_var = 100" ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "--------------------------------------------------\n" ] } ], "source": [ "print_fun(\"-\",50)" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "By default, python will let you read from a global, but not update it." ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "in function outer = -100.0\n", "outside, outer = -100.0\n" ] } ], "source": [ "outer = 1.0\n", "\n", "def update():\n", " # uncomment this to allow us to access outer in the calling namespace\n", " global outer\n", " outer = -100.0\n", " print(\"in function outer = {}\".format(outer))\n", " \n", "update()\n", "print(\"outside, outer = {}\".format(outer))" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "functions always return a value—if one is not explicitly given, then they return None, otherwise, they can return values (even multiple values) of any type" ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "in the function, i = 10\n", "None\n" ] } ], "source": [ "a = my_fun(10)\n", "print(a)" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "Here's a simple function that takes two numbers and returns their product." ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "12\n" ] } ], "source": [ "def multiply(a, b):\n", " return a*b\n", "\n", "c = multiply(3, 4)\n", "print(c)" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "

Quick Exercise:

\n", "\n", "Write a simple function that takes a sentence (as a string) and returns an integer equal to the length of the longest word in the sentence. The `len()` function and the `.split()` methods will be useful here.\n", "\n", "
" ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [ { "data": { "text/plain": [ "14" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "def max_len(s):\n", " l = -1\n", " for w in s.split():\n", " if len(w) > l:\n", " l = len(w)\n", " return l\n", "\n", "max_len(\"this is a test string with a random long word sasadfdfdsadaf\")" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "None is a special quantity in python (analogous to `null` in some other languages). We can test on `None`—the preferred manner is to use `is`:" ] }, { "cell_type": "code", "execution_count": 13, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "we didn't do anything\n" ] } ], "source": [ "def do_nothing():\n", " pass\n", "\n", "a = do_nothing()\n", "if a is None:\n", " print(\"we didn't do anything\")" ] }, { "cell_type": "code", "execution_count": 14, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a is None" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "## More Complex Functions\n", "\n", "Here's a more complex example. We return a pair of variables—behind the scenes in python this is done by packing them into a tuple and then unpacking on the calling end. Also note the _docstring_ here." ] }, { "cell_type": "code", "execution_count": 15, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "14\n", "[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233]\n" ] } ], "source": [ "def fib2(n): # return Fibonacci series up to n (from the python tutorial)\n", " \"\"\"Return a list containing the Fibonacci series up to n.\"\"\"\n", " result = []\n", " a, b = 0, 1\n", " while a < n:\n", " result.append(a) # see below\n", " a, b = b, a+b\n", " return result, len(result)\n", "\n", "fib, n = fib2(250)\n", "print(n)\n", "print(fib)" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "Note that this function includes a docstring (just after the function definition). This is used by the help system" ] }, { "cell_type": "code", "execution_count": 16, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Help on function fib2 in module __main__:\n", "\n", "fib2(n)\n", " Return a list containing the Fibonacci series up to n.\n", "\n" ] } ], "source": [ "help(fib2)" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "You can have optional arguments which provide defaults. Here's a simple function that validates an answer, with an optional argument that can provide the correct answer." ] }, { "cell_type": "code", "execution_count": 17, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "True\n", "False\n" ] } ], "source": [ "def check_answer(val, correct_answer=\"a\"):\n", " if val == correct_answer:\n", " return True\n", " else:\n", " return False\n", "\n", "print(check_answer(\"a\"))\n", "print(check_answer(\"a\", correct_answer=\"b\"))" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "it is important to note that python evaluates the optional arguments once—when the function is defined. This means that if you make the default an empty object, for instance, it will persist across all calls.\n", "\n", "** This leads to one of the most common errors for beginners **\n", "\n", "Here's an example of trying to initialize to an empty list:" ] }, { "cell_type": "code", "execution_count": 18, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[1]\n", "[1, 2]\n", "[1, 2, 3]\n" ] } ], "source": [ "def f(a, L=[]):\n", " L.append(a)\n", " return L\n", "\n", "print(f(1))\n", "print(f(2))\n", "print(f(3))" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "Notice that each call does not create its own separate list. Instead a single empty list was created when the function was first processed, and this list persists in memory as the default value for the optional argument `L`. \n", "\n", "If we want a unique list created each time (e.g., a separate place in memory), we instead initialize the argument's value to `None` and then check its actual value and create an empty list in the function body itself if the default value was unchanged." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true, "deletable": true, "editable": true }, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": 19, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[1]\n", "[2]\n", "[3]\n" ] } ], "source": [ "def fnew(a, L=None):\n", " if L is None:\n", " L = []\n", " L.append(a)\n", " return L\n", "\n", "print(fnew(1))\n", "print(fnew(2))\n", "print(fnew(3))" ] }, { "cell_type": "code", "execution_count": 20, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[1, 2]\n" ] } ], "source": [ "L = fnew(1)\n", "print(fnew(2, L=L))" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "Notice that the same `None` that we saw previously comes into play here. " ] }, { "cell_type": "code", "execution_count": 21, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "[1, 2]" ] }, "execution_count": 21, "metadata": {}, "output_type": "execute_result" } ], "source": [ "L" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "## Lambdas" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "Lambdas are \"disposible\" functions. These are small, nameless functions that are often used as arguments in other functions.\n", "\n", "Ex, from the official tutorial: we have a list of tuples. We want to sort the list based on the second item in the tuple. The `sort` method can take a `key` optional argument that tells us how to interpret the list item for sorting" ] }, { "cell_type": "code", "execution_count": 22, "metadata": { "collapsed": true, "deletable": true, "editable": true }, "outputs": [], "source": [ "pairs = [(1, 'one'), (2, 'two'), (3, 'three'), (4, 'four')]\n", "pairs.sort(key=lambda p: p[1])" ] }, { "cell_type": "code", "execution_count": 23, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [ { "data": { "text/plain": [ "[(4, 'four'), (1, 'one'), (3, 'three'), (2, 'two')]" ] }, "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], "source": [ "pairs" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "Here we use a lambda in an extract from a list (with the filter command)" ] }, { "cell_type": "code", "execution_count": 24, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [ { "data": { "text/plain": [ "[0,\n", " 36,\n", " 144,\n", " 324,\n", " 576,\n", " 900,\n", " 1296,\n", " 1764,\n", " 2304,\n", " 2916,\n", " 3600,\n", " 4356,\n", " 5184,\n", " 6084,\n", " 7056,\n", " 8100,\n", " 9216]" ] }, "execution_count": 24, "metadata": {}, "output_type": "execute_result" } ], "source": [ "squares = [x**2 for x in range(100)]\n", "sq = list(filter(lambda x : x%2 == 0 and x%3 == 0, squares))\n", "sq" ] }, { "cell_type": "code", "execution_count": 25, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Help on class filter in module builtins:\n", "\n", "class filter(object)\n", " | filter(function or None, iterable) --> filter object\n", " | \n", " | Return an iterator yielding those items of iterable for which function(item)\n", " | is true. If function is None, return the items that are true.\n", " | \n", " | Methods defined here:\n", " | \n", " | __getattribute__(self, name, /)\n", " | Return getattr(self, name).\n", " | \n", " | __iter__(self, /)\n", " | Implement iter(self).\n", " | \n", " | __new__(*args, **kwargs) from builtins.type\n", " | Create and return a new object. See help(type) for accurate signature.\n", " | \n", " | __next__(self, /)\n", " | Implement next(self).\n", " | \n", " | __reduce__(...)\n", " | Return state information for pickling.\n", "\n" ] } ], "source": [ "help(filter)" ] }, { "cell_type": "markdown", "metadata": { "collapsed": true, "deletable": true, "editable": true }, "source": [ "# Exceptions" ] }, { "cell_type": "markdown", "metadata": { "collapsed": true, "deletable": true, "editable": true }, "source": [ "Python raises exceptions when it encounters an error. The idea is that you can trap these exceptions and take an appropriate action instead of causing the code to crash. The mechanism for this is `try` / `except`. Here's an example that causes an exception, `ZeroDivisionError`:" ] }, { "cell_type": "code", "execution_count": 26, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [ { "ename": "ZeroDivisionError", "evalue": "division by zero", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mZeroDivisionError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0ma\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m/\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mZeroDivisionError\u001b[0m: division by zero" ] } ], "source": [ "a = 1/0" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "and here we handle this" ] }, { "cell_type": "code", "execution_count": 27, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "warning: you divided by zero\n" ] }, { "data": { "text/plain": [ "1" ] }, "execution_count": 27, "metadata": {}, "output_type": "execute_result" } ], "source": [ "try:\n", " a = 1/0\n", "except ZeroDivisionError:\n", " print(\"warning: you divided by zero\")\n", " a = 1\n", "\n", "a" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "another example—trying to access a key that doesn't exist in a dictionary:'" ] }, { "cell_type": "code", "execution_count": 28, "metadata": { "collapsed": true }, "outputs": [], "source": [ "dict = {\"a\":1, \"b\":2, \"c\":3}" ] }, { "cell_type": "code", "execution_count": 29, "metadata": { "collapsed": false }, "outputs": [ { "ename": "KeyError", "evalue": "'d'", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mKeyError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mv\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mdict\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m\"d\"\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mKeyError\u001b[0m: 'd'" ] } ], "source": [ "v = dict[\"d\"]" ] }, { "cell_type": "code", "execution_count": 30, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "None\n" ] } ], "source": [ "try:\n", " v = dict[\"d\"]\n", "except:\n", " v = None\n", "\n", "print(v)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [] } ], "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.3" } }, "nbformat": 4, "nbformat_minor": 1 }