{ "cells": [ { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Introduction to programming for Geoscientists through Python\n", "### [Gerard Gorman](http://www.imperial.ac.uk/people/g.gorman)\n", "\n", "# Lecture 3: Tuples, functions and if statements" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "Learning objectives:\n", "\n", "* Know how to modify elements in a list.\n", "* Be able iterate through different combinations of lists.\n", "* Know how to use a *tuple* to store data elements and understand how it differs from a *list*.\n", "* Be able to write your own *function*.\n", "* Know the difference between a locally-scoped and globally-scoped variables.\n", "* Be able to use an *if* statement to execute some code blocks conditionally." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Changing elements in a list\n", "Say we want to add $2$ to all the numbers in a list:" ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[-1, 1, 10]\n" ] } ], "source": [ "v = [-1, 1, 10]\n", "for e in v:\n", " e=e+2\n", "print(v)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "We can see that the list *v* is unaltered! The reason for this is that inside the loop, *e* is an ordinary (int) variable. At the start of the iteration *e* is assigned a *copy* of the next element in the list. Inside the loop we can change *e* but *v* itself is unaltered. If we want to change *v* we have to use an index to access and modify its elements:" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[-1, 4, 10]\n" ] } ], "source": [ "v[1] = 4 # assign 4 to 2nd element (index 1) in v\n", "print(v)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "To add 2 to all values we need a *for* loop over indices:" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[1, 6, 12]\n" ] } ], "source": [ "for i in range(len(v)):\n", " v[i] = v[i] + 2\n", "print(v)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Traversing multiple lists simultaneously - *zip(list1, list2, ...)*\n", "Consider how we can loop over elements in both Cdegrees and Fdegrees at the same time. One approach would be to use list indices:" ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "-20 -4.0\n", "-15 5.0\n", "-10 14.0\n", "-5 23.0\n", "0 32.0\n", "5 41.0\n", "10 50.0\n", "15 59.0\n", "20 68.0\n", "25 77.0\n", "30 86.0\n", "35 95.0\n", "40 104.0\n" ] } ], "source": [ "# First we have to recreate the data from the previous lecture\n", "Cdegrees = [deg for deg in range(-20, 41, 5)]\n", "Fdegrees = [(9/5)*deg + 32 for deg in Cdegrees]\n", "\n", "for i in range(len(Cdegrees)):\n", " print(Cdegrees[i], Fdegrees[i])" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "An alternative construct (regarded as more ”Pythonic”) uses the *zip* function:" ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "-20 -4.0\n", "-15 5.0\n", "-10 14.0\n", "-5 23.0\n", "0 32.0\n", "5 41.0\n", "10 50.0\n", "15 59.0\n", "20 68.0\n", "25 77.0\n", "30 86.0\n", "35 95.0\n", "40 104.0\n" ] } ], "source": [ "for C, F in zip(Cdegrees, Fdegrees):\n", " print(C, F)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "Another example with three lists:" ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "3 1.5 9.1\n", "6 1 3\n", "1 0 2\n" ] } ], "source": [ "l1 = [3, 6, 1]; l2 = [1.5, 1, 0]; l3 = [9.1, 3, 2]\n", "for e1, e2, e3 in zip(l1, l2, l3):\n", " print(e1, e2, e3)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "If the lists are of unequal length then the loop stops when the end of the shortest list is reached. Experiment with this:" ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "3 1.5 9.1\n", "6 1 3\n", "1 0 2\n", "4 7 0\n" ] } ], "source": [ "l1 = [3, 6, 1, 4, 6]; l2 = [1.5, 1, 0, 7]; l3 = [9.1, 3, 2, 0, 9]\n", "for e1, e2, e3 in zip(l1, l2, l3):\n", " print(e1, e2, e3)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Nested lists: list of lists\n", "A *list* can contain **any** object, including another *list*. To illustrate this, consider how to store the conversion table as a single Python list rather than two separate lists." ] }, { "cell_type": "code", "execution_count": 13, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "table1 = [range(-20, 41, 5), [-4.0, 5.0, 14.0, 23.0, 32.0, 41.0, 50.0, 59.0, 68.0, 77.0, 86.0, 95.0, 104.0]]\n", "table1[0] = range(-20, 41, 5)\n", "table1[1] = [-4.0, 5.0, 14.0, 23.0, 32.0, 41.0, 50.0, 59.0, 68.0, 77.0, 86.0, 95.0, 104.0]\n", "table1[2][3] = 23.0\n" ] } ], "source": [ "Cdegrees = range(-20, 41, 5)\n", "Fdegrees = [(9.0/5)*C + 32 for C in Cdegrees]\n", "table1 = [Cdegrees, Fdegrees] # List of two lists\n", "print(\"table1 = \", table1)\n", "print(\"table1[0] = \", table1[0])\n", "print(\"table1[1] = \", table1[1])\n", "print(\"table1[1][3] = \", table1[1][3])" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "This gives us a table of two rows. How do we create a table of columns instead:" ] }, { "cell_type": "code", "execution_count": 14, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[[-20, -4.0], [-15, 5.0], [-10, 14.0], [-5, 23.0], [0, 32.0], [5, 41.0], [10, 50.0], [15, 59.0], [20, 68.0], [25, 77.0], [30, 86.0], [35, 95.0], [40, 104.0]]\n" ] } ], "source": [ "table2 = []\n", "for C, F in zip(Cdegrees, Fdegrees):\n", " row = [C, F]\n", " table2.append(row)\n", "print(table2)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "We can use list comprehension to do this more elegantly:" ] }, { "cell_type": "code", "execution_count": 15, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[[-20, -4.0], [-15, 5.0], [-10, 14.0], [-5, 23.0], [0, 32.0], [5, 41.0], [10, 50.0], [15, 59.0], [20, 68.0], [25, 77.0], [30, 86.0], [35, 95.0], [40, 104.0]]\n" ] } ], "source": [ "table2 = [[C, F] for C, F in zip(Cdegrees, Fdegrees)]\n", "print(table2)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "And you can loop through this list as before:" ] }, { "cell_type": "code", "execution_count": 16, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "-20 -4.0\n", "-15 5.0\n", "-10 14.0\n", "-5 23.0\n", "0 32.0\n", "5 41.0\n", "10 50.0\n", "15 59.0\n", "20 68.0\n", "25 77.0\n", "30 86.0\n", "35 95.0\n", "40 104.0\n" ] } ], "source": [ "for C, F in table2:\n", " print(C, F)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Tuples: lists that cannot be changed\n", "Tuples are **constant** lists, i.e. you can use them in much the same way as lists except you cannot modify them. They are an example of an [**immutable**](http://en.wikipedia.org/wiki/Immutable_object) type." ] }, { "cell_type": "code", "execution_count": 17, "metadata": { "collapsed": true, "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "t = (2, 4, 6, 'temp.pdf') # Define a tuple.\n", "t = 2, 4, 6, 'temp.pdf' # Can skip parenthesis as it is assumed in this context." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "Let's see what happens when we try to modify the tuple like we did with a list:" ] }, { "cell_type": "code", "execution_count": 18, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "ename": "TypeError", "evalue": "'tuple' object does not support item assignment", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mTypeError\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[0mt\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m-\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mTypeError\u001b[0m: 'tuple' object does not support item assignment" ] } ], "source": [ "t[1] = -1" ] }, { "cell_type": "code", "execution_count": 19, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "ename": "AttributeError", "evalue": "'tuple' object has no attribute 'append'", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mAttributeError\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[0mt\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mappend\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mAttributeError\u001b[0m: 'tuple' object has no attribute 'append'" ] } ], "source": [ "t.append(0)" ] }, { "cell_type": "code", "execution_count": 20, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "ename": "TypeError", "evalue": "'tuple' object doesn't support item deletion", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mTypeError\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[0;32mdel\u001b[0m \u001b[0mt\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mTypeError\u001b[0m: 'tuple' object doesn't support item deletion" ] } ], "source": [ "del t[1]" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "However, we can use the tuple to compose a new tuple:" ] }, { "cell_type": "code", "execution_count": 21, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "(2, 4, 6, 'temp.pdf', -1.0, -2.0)\n" ] } ], "source": [ "t = t + (-1.0, -2.0)\n", "print(t)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "So, why would we use tuples when lists have more functionality?\n", "\n", "* Tuples are constant and thus protected against accidental changes.\n", "* Tuples are faster than lists.\n", "* Tuples are widely used in Python software (so you need to know about tuples to understand other people's code!)\n", "* Tuples (but not lists) can be used as keys in dictionaries (more about dictionaries later)." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Exercise 3.1: Make a table of function values\n", "Step 1: Write a program that prints a table with $t$ values in the first column and the corresponding $y(t) = v_0 t − 0.5gt^2$ values in the second column. Use $n$ uniformly spaced $t$ values throughout the interval [0, $2v_0/g$]. Set $v0 = 1$, $g = 9.81$, and $n = 11$.\n", "\n", "Step 2: Once step 1 is working, modify the program so that the $t$ and $y$ values are stored in two lists *t* and *y*. Thereafter, transverse the lists with a *for* loop and write out a nicely formatted table of *t* and *y* values using a *zip* construction." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true, "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Functions\n", "We have already used many Python functions, e.g. mathematical functions:" ] }, { "cell_type": "code", "execution_count": 22, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "-1.0\n" ] } ], "source": [ "from math import *\n", "x = pi\n", "print(cos(x))" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "Other functions you used include *len* and *range*:" ] }, { "cell_type": "code", "execution_count": 24, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "range(5, 10, 2)\n", "3\n" ] } ], "source": [ "somelist = range(5, 10, 2)\n", "print(somelist)\n", "print(len(somelist))" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "You have also used functions that are executed with the dot syntax (called *methods*):" ] }, { "cell_type": "code", "execution_count": 25, "metadata": { "collapsed": true, "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "C = [5, 10, 40, 45]\n", "i = C.index(10)\n", "C.append(50)\n", "C.insert(2, 20)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "A function is a collection of statements we can execute wherever and whenever we want. Functions can take any number of inputs (called *arguments*) to produce outputs. Functions help to organize programs, make them more understandable, shorter, and easier to extend. For our first example we will turn our temperature conversion code into a function:" ] }, { "cell_type": "code", "execution_count": 26, "metadata": { "collapsed": true, "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "def C2F(C):\n", " return (9.0/5)*C + 32" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "Functions start with *def*, then the name you want to give your function, then a list of arguments (here C). This is referred to as the *function header*. Inside the function there is a block of statements called the *function body*. Notice that the function body is indented - as was the case for the *for* / *while* loop the indentation indicates where the function ends. At any point within the function, we can \"stop the\n", "function\" and return as many values/variables as required." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Local and global variables\n", "Variables defined within a function are said to have *local scope*. That is to say that they can only be referenced within that function. Let's consider an example (and look carefully at the indentation!!):" ] }, { "cell_type": "code", "execution_count": 27, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "15\n" ] } ], "source": [ "def sumint(start, stop):\n", " s = 0 # variable for accumulating the sum\n", " i = start # counter\n", " while i <= stop:\n", " s += i\n", " i += 1\n", " return s\n", "\n", "print(sumint(0, 5))" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "Variables *i* and *s* are local variables in *sumint*. They are destroyed at the end (return) of the function and never visible outside the function (in the calling program); in fact, *start* and *stop* are also local variables. So let's see what happens if we now try to print one of these variables:" ] }, { "cell_type": "code", "execution_count": 28, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "ename": "NameError", "evalue": "name 'stop' is not defined", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mNameError\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[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mstop\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mNameError\u001b[0m: name 'stop' is not defined" ] } ], "source": [ "print(stop)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "Functions can also return multiple values. Let's recycle another of our previous examples - compute $y(t)$ and $y'(t)=v_0-gt$:" ] }, { "cell_type": "code", "execution_count": 29, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0.034199999999999786 -2.886\n" ] } ], "source": [ "def yfunc(t, v0):\n", " g = 9.81\n", " y = v0*t - 0.5*g*t**2\n", " dydt = v0 - g*t\n", " return y, dydt\n", "\n", "# call:\n", "position, velocity = yfunc(0.6, 3)\n", "\n", "print(position, velocity)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "Remember that a series of comma separated variables implies a tuple - therefore \"return y, dydt\" is the same as writing \"return (y, dydt)\". Therefore, in general what is returned is a tuple. Let's take a look at another example illustrating this:" ] }, { "cell_type": "code", "execution_count": 30, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "(2, 4, 16)\n", "\n" ] } ], "source": [ "def f(x):\n", " return x, x**2, x**4\n", "s = f(2)\n", "print(s)\n", "print(type(s)) # The function type() tells us what type a variable it is." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "No return value implies that *None* is returned. *None* is a special Python object that represents an ”empty” or undefined value. It is surprisingly useful and we will use it a lot later." ] }, { "cell_type": "code", "execution_count": 31, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Python rocks!\n", "Geo rocks!\n", "r = None\n" ] } ], "source": [ "def message(course):\n", " print(\"%s rocks!\"% course)\n", "\n", "message(\"Python\")\n", "\n", "r = message(\"Geo\")\n", "\n", "print(\"r = \", r)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Keyword arguments and default input values\n", "Functions can have arguments of the form variable_name=value and are called keyword arguments:" ] }, { "cell_type": "code", "execution_count": 32, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Hello [1, 2] True 0\n" ] } ], "source": [ "def somefunc(arg1, arg2, kwarg1=True, kwarg2=0):\n", " print(arg1, arg2, kwarg1, kwarg2)\n", "\n", "somefunc(\"Hello\", [1,2]) # Note that we have not specified inputs for kwarg1 and kwarg2" ] }, { "cell_type": "code", "execution_count": 33, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Hello [1, 2] Hi 0\n" ] } ], "source": [ "somefunc(\"Hello\", [1,2], kwarg1=\"Hi\")" ] }, { "cell_type": "code", "execution_count": 34, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Hello [1, 2] True Hi\n" ] } ], "source": [ "somefunc(\"Hello\", [1,2], kwarg2=\"Hi\")" ] }, { "cell_type": "code", "execution_count": 35, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Hello [1, 2] 6 Hi\n" ] } ], "source": [ "somefunc(\"Hello\", [1,2], kwarg2=\"Hi\", kwarg1=6)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "If we use variable_name=value for all arguments, their sequence in the function header can be in any order." ] }, { "cell_type": "code", "execution_count": 36, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Hi [2] 6 Hello\n" ] } ], "source": [ "somefunc(kwarg2=\"Hello\", arg1=\"Hi\", kwarg1=6, arg2=[2])" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "Let's look at another example - consider a function of $t$, with parameters $A$, $a$, and $\\omega$:\n", "$$f(t; A,a, \\omega) = Ae^{-at}\\sin (\\omega t)$$. (The choice of equation is actually pretty random - but it serves to show you that it is easy to translate formulae you encounter into Python code). We can implement $f$ in a Python function with $t$ as positional argument and $A$, $a$, and $\\omega$ as keyword arguments." ] }, { "cell_type": "code", "execution_count": 37, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0.778659217806053 0.5219508827258282 0.40664172703834794 4.230480200204721 7.007932960254476\n" ] } ], "source": [ "from math import pi, exp, sin\n", "def f(t, A=1, a=1, omega=2*pi):\n", " return A*exp(-a*t)*sin(omega*t)\n", "\n", "v1 = f(0.2)\n", "v2 = f(0.2, omega=1)\n", "v2 = f(0.2, 1, 3) # same as f(0.2, A=1, a=3)\n", "v3 = f(0.2, omega=1, A=2.5)\n", "v4 = f(A=5, a=0.1, omega=1, t=1.3)\n", "v5 = f(t=0.2, A=9)\n", "\n", "print(v1, v2, v3, v4, v5)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Convention for input and output data in functions\n", "A function can have three types of input and output data:\n", "\n", "* Input data specified through positional/keyword arguments.\n", "* Input/output data given as positional/keyword arguments that will be modified and returned.\n", "* Output data created inside the function.\n", "\n", "All output data are returned, all input data are arguments.\n", "\n", "Sketch of a general Python function:" ] }, { "cell_type": "raw", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "def somefunc(i1, i2, i3, io4, io5, i6=value1, io7=value2):\n", " # modify io4, io5, io7; compute o1, o2, o3\n", " return o1, o2, o3, io4, io5, io7\n", " \n", "* i1, i2, i3, i6: pure input data\n", "* io4, io5, io7: input and output data\n", "* o1, o2, o3: pure output data" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Exercise 3.2: Implement a Gaussian function\n", "\n", "Make a Python function *gauss*( *x*, *m*=0, *s*=1) for computing the Gaussian function \n", "$$f(x)=\\frac{1}{\\sqrt{2\\pi}s}\\exp\\left(-\\frac{1}{2} \\left(\\frac{x-m}{s}\\right)^2\\right)$$\n", "Call the function and print out the result for x equal to −5, −4.9, −4.8, ..., 4.8, 4.9, 5, using default values for *m* and *s*.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true, "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## The *if* construct\n", "Consider this simple example:" ] }, { "cell_type": "code", "execution_count": 38, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0 1.0 0\n" ] } ], "source": [ "def f(x):\n", " if 0 <= x <= pi:\n", " return sin(x)\n", " else:\n", " return 0\n", "print(f(-pi/2), f(pi/2), f(3*pi/2))" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "Sometimes it is clearer to write this as an *inline* statement:" ] }, { "cell_type": "code", "execution_count": 39, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0 1.0 0\n" ] } ], "source": [ "def f(x):\n", " return (sin(x) if 0 <= x <= pi else 0)\n", "print(f(-pi/2), f(pi/2), f(3*pi/2))" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "In general (the *else* block can be skipped if there are no statements to be executed when False) we can put together multiple conditions. Only the first condition that is True is executed.\n", "\n", "```\n", "if condition1:\n", " \n", "elif condition2:\n", " \n", "elif condition3:\n", " \n", "else:\n", " \n", " \n", "\n", "```" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Exercise 3.3: Express a step function as a Python function\n", "The following \"step\" function is known as the Heaviside function and\n", "is widely used in mathematics:\n", "$$H(x)=\\begin{cases}0, & \\text{if $x<0$}.\\\\\\\\\n", "1, & \\text{if $x\\ge 0$}.\\end{cases}$$\n", "Write a Python function H(x) that computes H(x)." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true, "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [] } ], "metadata": { "celltoolbar": "Slideshow", "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": 1 }