diff --git a/ch02-python.ipynb b/ch02-python.ipynb index 42f9eb3..7cd5814 100644 --- a/ch02-python.ipynb +++ b/ch02-python.ipynb @@ -1,1023 +1,579 @@ { + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print(\"Hello Sir Newton.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "What to write in the terminal:\n", + "\n", + "```\n", + "$ ipython\n", + "Python 2.7.5+ (default, Sep 19 2013, 13:48:49) \n", + "Type \"copyright\", \"credits\" or \"license\" for more information.\n", + "\n", + "IPython 1.1.0 -- An enhanced Interactive Python.\n", + "? -> Introduction and overview of IPython's features.\n", + "%quickref -> Quick reference.\n", + "help -> Python's own help system.\n", + "object? -> Details about 'object', use 'object??' for extra details.\n", + "\n", + "In [1]: print(\"Good day, Madam Curie.\")\n", + "Good day, Madam Curie.\n", + "\n", + "In [2]: \n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print(\"Hey Isaac, what's Newton?!\")\n", + "print(\"How is it going, Gottfried?\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "h_bar = 1.05457e-34 # measured in J*s or n*m*s or kg*m^2/s, same dimensions as angular momentum" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "2plus_forty = 42 # bad idea to start a variable name with a number" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "two_plus40 = 42 # good way to put a number in a variable name is to have it anywhere but the 0th character" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "pi = 3.14159\n", + "h = 2 * pi * h_bar\n", + "print(h)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "dims = 3 # int, only digits\n", + "ndim = 3.0 # float, because of the '.'\n", + "h_bar = 1.05457e-34 # float, because of the '.' or 'e'\n", + "label = \"Energy (in MeV)\" # str, quotes surround the text" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "type(h_bar)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "type(42)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "float(42)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "int(\"28\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "int(\"quark\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "x = 3\n", + "x = 1.05457e-34\n", + "x = \"Energy (in MeV)\" " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "bool(0)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "bool(\"Do we need Oxygen?\") # returns true because the string is not empty" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "\"Gorgus\" / 2.718 " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "x = 1 # Create x\n", + "del x # Destroy x" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "x = (42 * 65) - 1 # A simple statement" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "42 + 65 # A subexpression found in the previous statement" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "(42 + 65) + 1 # A longer subexpression that includes the previous subexpression" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "x = \"Nature abhors a vacuum\" # You may use double quotes around a string\n", + "y = 'but loves a mop!' # also works, but may cause issues if there are apostrophes in the string" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "p = \"proton\" # Strings are unicode in python3, python2 strings can be made unicode by prepending u as in p = u\"python\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "p[1] # Index starts at 0" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "p[-1] # It is often convenient to use a negative index" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "p[len(p)-2] # Also works, but why write len(p) all the time?" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "p[2:5] # Slices are defined to be inclusive on the lower end and exclusive on the upper end" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "p[1:-1] # a slice is defined by [start,stop)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "p[-1:2] # the slice will not wrap around the left or right edges of the sequence" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "q = \"AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "q[2:-2:2] # The syntax of the slice is [Start: Stop: Step]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "q[1::2] # The default value of Stop is len(q)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "q[::-3] # Step may be negative" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "x = \"neveroddoreven\"\n", + "x == x[::-1] # This is the easiest way to reverse a string or list" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "my_slice = slice(3, 1415, 9) # my slice of the pi\n", + "x[my_slice] # The values of x at indices 3 and 9" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "\"kilo\" + \"meter\" # String concatenation" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "\"x^\" + str(2) " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "\"newto\" * 10 # String manipulation" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "\"H + H\" \" -> H2\" # Putting two string literals next to each other concatenates them by default" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "quote = (\"Science is what we understand well enough to explain to a computer. \"\n", + " \"Art is everything else we do. \"\n", + " \"-Donald Knuth\") # Strings are not interrupted by newlines" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "x = \"It's easy!\"\n", + "y = 'The computer said, \"Does not compute.\"' # Be careful with single and double quptes" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "\"Bones said, \\\"He\\'s dead, Jim.\\\"\" # The backslash can fix problems with quotes inside strings" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "\"\"\"Humpty, he sat on a wall, \n", + "Then Humpty, he had a great fall.\n", + "But all the king's horses\n", + "And men with their forces\n", + "Couldn't render his entropy small.\n", + "\"\"\" # Triple doubles create a multiline string, which is essential in documentation" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "header = \" temperature pressure\\t value \\n\" # The extra whitespace at the beginning and end here looks annoying" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "header.strip() # The strip() method is incredibly useful for normalizing text-based data." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "header.upper() #Returns header only with capital letters" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "\"10\".isdigit() # Every character in this string is a digit" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "\"10.10\".isdigit() # Not every character in this string is a digit" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "\"{0} gets into work & then his {1} begins!\".format(\"Hilbert\", \"commute\") # This helps convert data to strings without excess type conversion and concatenation." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "x = 42\n", + "y = 65.0" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "\"x={0} y={1}\".format(x, y)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "\"x=\" + str(x) + \" y=\" + str(y) # This is equivalent to using the format method but requires more type conversion" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import constants # Imports all the variables in the constants module\n", + "\n", + "two_pi = 2 * constants.pi\n", + "h_bar = constants.h / two_pi" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from constants import pi, h # Imports only the requested variables from the constants module\n", + "\n", + "two_pi = 2 * pi\n", + "h_bar = h / two_pi" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import constants as c # Aliases the constants module\n", + "\n", + "constants = 2.71828\n", + "\n", + "two_pi = 2 * c.pi\n", + "h_bar = c.h / 2 / c.pi" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from constants import pi as PI, h as H # Aliases the variables that are imported from the constants module\n", + "\n", + "two_pi = 2 * PI\n", + "h_bar = H / two_pi" + ] + } + ], "metadata": { - "name": "", - "signature": "sha256:ac035f16465ad55f7f1cbb1dc173d13d32a2f1d9a63b9d5f3e0f5eadb2b57b00" - }, - "nbformat": 3, - "nbformat_minor": 0, - "worksheets": [ - { - "cells": [ - { - "cell_type": "code", - "collapsed": false, - "input": [ - "print(\"Hello Sir Newton.\")" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "Hello Sir Newton.\n" - ] - } - ], - "prompt_number": 1 - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "What to write in the terminal:\n", - "\n", - "```\n", - "$ ipython\n", - "Python 2.7.5+ (default, Sep 19 2013, 13:48:49) \n", - "Type \"copyright\", \"credits\" or \"license\" for more information.\n", - "\n", - "IPython 1.1.0 -- An enhanced Interactive Python.\n", - "? -> Introduction and overview of IPython's features.\n", - "%quickref -> Quick reference.\n", - "help -> Python's own help system.\n", - "object? -> Details about 'object', use 'object??' for extra details.\n", - "\n", - "In [1]: print(\"Good day, Madam Curie.\")\n", - "Good day, Madam Curie.\n", - "\n", - "In [2]: \n", - "```" - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "print(\"Hey Isaac, what's Newton?!\")\n", - "print(\"How is it going, Gottfried?\")" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "Hey Isaac, what's Newton?!\n", - "How is it going, Gottfried?\n" - ] - } - ], - "prompt_number": 2 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "h_bar = 1.05457e-34" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 3 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "2plus_forty = 42 # bad" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "ename": "SyntaxError", - "evalue": "invalid syntax (, line 1)", - "output_type": "pyerr", - "traceback": [ - "\u001b[1;36m File \u001b[1;32m\"\"\u001b[1;36m, line \u001b[1;32m1\u001b[0m\n\u001b[1;33m 2plus_forty = 42 # bad\u001b[0m\n\u001b[1;37m ^\u001b[0m\n\u001b[1;31mSyntaxError\u001b[0m\u001b[1;31m:\u001b[0m invalid syntax\n" - ] - } - ], - "prompt_number": 4 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "two_plus40 = 42 # good" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 5 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "pi = 3.14159\n", - "h = 2 * pi * h_bar\n", - "print(h)" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "6.6260531326e-34\n" - ] - } - ], - "prompt_number": 6 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "dims = 3 # int, only digits\n", - "ndim = 3.0 # float, because of the '.'\n", - "h_bar = 1.05457e-34 # float, because of the '.' or 'e'\n", - "label = \"Energy (in MeV)\" # str, quotes surround the text" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 7 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "type(h_bar)" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 8, - "text": [ - "float" - ] - } - ], - "prompt_number": 8 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "type(42)" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 9, - "text": [ - "int" - ] - } - ], - "prompt_number": 9 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "float(42)" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 10, - "text": [ - "42.0" - ] - } - ], - "prompt_number": 10 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "int(\"28\")" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 11, - "text": [ - "28" - ] - } - ], - "prompt_number": 11 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "int(\"quark\")" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "ename": "ValueError", - "evalue": "invalid literal for int() with base 10: 'quark'", - "output_type": "pyerr", - "traceback": [ - "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[1;31mValueError\u001b[0m Traceback (most recent call last)", - "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[0mint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m\"quark\"\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", - "\u001b[1;31mValueError\u001b[0m: invalid literal for int() with base 10: 'quark'" - ] - } - ], - "prompt_number": 12 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "x = 3\n", - "x = 1.05457e-34\n", - "x = \"Energy (in MeV)\"" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 13 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "bool(0)" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 14, - "text": [ - "False" - ] - } - ], - "prompt_number": 14 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "bool(\"Do we need Oxygen?\")" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 15, - "text": [ - "True" - ] - } - ], - "prompt_number": 15 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "\"Gorgus\" / 2.718" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "ename": "TypeError", - "evalue": "unsupported operand type(s) for /: 'str' and 'float'", - "output_type": "pyerr", - "traceback": [ - "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[1;31mTypeError\u001b[0m Traceback (most recent call last)", - "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[1;34m\"Gorgus\"\u001b[0m \u001b[1;33m/\u001b[0m \u001b[1;36m2.718\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", - "\u001b[1;31mTypeError\u001b[0m: unsupported operand type(s) for /: 'str' and 'float'" - ] - } - ], - "prompt_number": 16 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "x = 1 # Create x\n", - "del x # Destroy x" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 17 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "x = (42 * 65) - 1" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 18 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "42 + 65" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 19, - "text": [ - "107" - ] - } - ], - "prompt_number": 19 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "(42 + 65) + 1" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 20, - "text": [ - "108" - ] - } - ], - "prompt_number": 20 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "x = \"Nature abhors a vacuum\"\n", - "y = 'but loves a mop!'" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 21 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "p = \"proton\"" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 22 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "p[1]" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 23, - "text": [ - "'r'" - ] - } - ], - "prompt_number": 23 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "p[-1]" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 24, - "text": [ - "'n'" - ] - } - ], - "prompt_number": 24 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "p[len(p)-2] # also works, but why write len(p) all the time?" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 25, - "text": [ - "'o'" - ] - } - ], - "prompt_number": 25 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "p[2:5]" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 26, - "text": [ - "'oto'" - ] - } - ], - "prompt_number": 26 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "p[1:-1]" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 27, - "text": [ - "'roto'" - ] - } - ], - "prompt_number": 27 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "p[-1:2]" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 28, - "text": [ - "''" - ] - } - ], - "prompt_number": 28 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "q = \"AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz\"" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 29 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "q[2:-2:2]" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 30, - "text": [ - "'BCDEFGHIJKLMNOPQRSTUVWXY'" - ] - } - ], - "prompt_number": 30 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "q[1::2]" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 31, - "text": [ - "'abcdefghijklmnopqrstuvwxyz'" - ] - } - ], - "prompt_number": 31 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "q[::-3]" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 32, - "text": [ - "'zYwVtSqPnMkJhGeDbA'" - ] - } - ], - "prompt_number": 32 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "x = \"neveroddoreven\"\n", - "x == x[::-1]" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 33, - "text": [ - "True" - ] - } - ], - "prompt_number": 33 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "my_slice = slice(3, 1415, 9) # my slice of the pi\n", - "x[my_slice]" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 34, - "text": [ - "'ee'" - ] - } - ], - "prompt_number": 34 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "\"kilo\" + \"meter\" " - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 35, - "text": [ - "'kilometer'" - ] - } - ], - "prompt_number": 35 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "\"x^\" + str(2) " - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 36, - "text": [ - "'x^2'" - ] - } - ], - "prompt_number": 36 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "\"newto\" * 10" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 37, - "text": [ - "'newtonewtonewtonewtonewtonewtonewtonewtonewtonewto'" - ] - } - ], - "prompt_number": 37 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "\"H + H\" \" -> H2\"" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 38, - "text": [ - "'H + H -> H2'" - ] - } - ], - "prompt_number": 38 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "quote = (\"Science is what we understand well enough to explain to a computer. \"\n", - " \"Art is everything else we do. \"\n", - " \"-Donald Knuth\")" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 39 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "x = \"It's easy!\"\n", - "y = 'The computer said, \"Does not compute.\"'" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 40 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "\"Bones said, \\\"He\\'s dead, Jim.\\\"\"" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 41, - "text": [ - "'Bones said, \"He\\'s dead, Jim.\"'" - ] - } - ], - "prompt_number": 41 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "\"\"\"Humpty, he sat on a wall,\n", - "Then Humpty, he had a great fall.\n", - "But all the king's horses\n", - "And men with their forces\n", - "Couldn't render his entropy small.\n", - "\"\"\"" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 42, - "text": [ - "\"Humpty, he sat on a wall,\\nThen Humpty, he had a great fall.\\nBut all the king's horses\\nAnd men with their forces\\nCouldn't render his entropy small.\\n\"" - ] - } - ], - "prompt_number": 42 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "header = \" temperature pressure\\t value \\n\"" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 43 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "header.strip()" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 44, - "text": [ - "'temperature pressure\\t value'" - ] - } - ], - "prompt_number": 44 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "header.upper()" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 45, - "text": [ - "' TEMPERATURE PRESSURE\\t VALUE \\n'" - ] - } - ], - "prompt_number": 45 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "\"10\".isdigit()" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 46, - "text": [ - "True" - ] - } - ], - "prompt_number": 46 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "\"10.10\".isdigit()" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 47, - "text": [ - "False" - ] - } - ], - "prompt_number": 47 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "\"{0} gets into work & then his {1} begins!\".format(\"Hilbert\", \"commute\")" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 48, - "text": [ - "'Hilbert gets into work & then his commute begins!'" - ] - } - ], - "prompt_number": 48 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "x = 42\n", - "y = 65.0" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 49 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "\"x={0} y={1}\".format(x, y)" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 50, - "text": [ - "'x=42 y=65.0'" - ] - } - ], - "prompt_number": 50 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "\"x=\" + str(x) + \" y=\" + str(y)" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 51, - "text": [ - "'x=42 y=65.0'" - ] - } - ], - "prompt_number": 51 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "import constants\n", - "\n", - "two_pi = 2 * constants.pi\n", - "h_bar = constants.h / two_pi" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 52 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "from constants import pi, h\n", - "\n", - "two_pi = 2 * pi\n", - "h_bar = h / two_pi" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 53 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "import constants as c\n", - "\n", - "constants = 2.71828\n", - "\n", - "two_pi = 2 * c.pi\n", - "h_bar = c.h / 2 / c.pi" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 54 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "from constants import pi as PI, h as H\n", - "\n", - "two_pi = 2 * PI\n", - "h_bar = H / two_pi" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 55 - } - ], - "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.6" } - ] -} \ No newline at end of file + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/ch03-containers.ipynb b/ch03-containers.ipynb index 77aaaf1..550ad5a 100644 --- a/ch03-containers.ipynb +++ b/ch03-containers.ipynb @@ -1,768 +1,753 @@ { + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Containers in Python " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Lists" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Lists in Python are one-dimensional, ordered containers whose elements may be any\n", + "Python objects. Lists are mutable and have methods for adding and removing elements to and from themselves." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "[6, 28]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "[1e3, -2, \"I am in a list.\"]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "[[1.0, 0.0], [0.0, 1.0]]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The following cell demonstrates list concatenation:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "[1, 1] + [2, 3, 5] + [8]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "fib = [1, 1, 2, 3, 5, 8]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The append() method is used to add one element to the list" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "fib.append(13)\n", + "fib" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The extend() method and the += operator can be used to add multiple elements to the list" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "fib.extend([21, 34, 55])\n", + "fib" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "fib += [89, 144]\n", + "fib" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "List indexing works like string indexing (see page 50)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "fib[::2]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Lists are mutable and their elements may be changed in place with indexing:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "fib[3] = \"whoops\"\n", + "fib" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "del fib[:5]\n", + "fib" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "fib[1::2] = [-1, -1, -1] \n", + "fib " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The same multiplacation-by-an-integer trick for strings works for lists:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "[1, 2, 3] * 6" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You can also create lists of characters directly from strings by using the list() conversion function:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "list(\"F = dp/dt\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Another fascinating property is that a list will infinitely recurse if you add it to itself because python is reference-counted, which means that variable names are actually references to the underlying values. The language then keeps an internal count of how many times a reference has been used and what its names are." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "x = []\n", + "x.append(x)\n", + "x" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "x[0]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "x[0][0]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If y = x, deleting x does not delete y:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "x = 42\n", + "y = x\n", + "del x" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "However, changing y will change x. This is the spooky action at a distance of programming." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "x = [3, 2, 1, \"blast off!\"]\n", + "y = x\n", + "y[1] = \"TWO\"\n", + "print(x)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Tuples" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Tuples are immutable lists, defined by their commas. They often have parentheses around them. Tuples may be concatenated just like strings, but be careful about the order of operations." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "a = 1, 2, 5, 3 # length-4 tuple\n", + "b = (42,) # length-1 tuple, defined by comma\n", + "c = (42) # not a tuple, just the number 42\n", + "d = () # length-0 tuple- no commas means no elements" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "(1, 2) + (3, 4)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "1, 2 + 3, 4" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The tuple converter is used to make a list immutable:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "tuple([\"e\", 2.718])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Tuples are immutable, but their elements may be mutable:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "x = 1.0, [2, 4], 16\n", + "x[1].append(8)\n", + "x" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Sets" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Sets are comma separated values between curly braces {}. They are unordered containers of unique values. Duplicate values are ignored. Sets cannot be indexed." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# a literal set formed with elements of various types\n", + "{1.0, 10, \"one hundred\", (1, 0, 0,0)}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# a literal set of special values\n", + "{True, False, None, \"\", 0.0, 0}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# conversion from a list to a set\n", + "set([2.0, 4, \"eight\", (16,)])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The set of a string is actually the set of its characters, because a string is a sequence" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "set(\"Marie Curie\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To make a set of a full string, first put the string inside another sequence" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "set([\"Marie Curie\"])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "s = {1, 2, 3}\n", + "t = {3, 4, 5}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "s | t # union" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "s & t # intersection" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "s - t # difference" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "s ^ t # symmetric difference" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "s < t # strict subset" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "s <= t # subset" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "s > t # strict superset" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "s >= t # strict superset" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The elements of a set must all be hashable , which is to say they can be used in the hash() function without failure. The following logic statement is generally true, for objects of the same type:\n", + "\n", + "hash(x) == hash(y) implies that x == y" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "hash(1234567)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "hash('i like turtles')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "hash('i like fifa')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "hash(0)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "hash('') # hash ('') == hash(0) does not follow the logic statement above because the arguments are different types" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Dictionaries" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Dictionaries, or dicts, are the most important data structure. They are python's native implementation of a hash table. A dictionary, or dict is a mutable, unordered list of key/value pairs.\n", + "\n", + "Keys are hashable, unique objects. Anything can be a value. Values may be non-unique. Many unique keys may have the same value. Dictionaries are the fastest and easiest way to store and look up a value.\n", + "\n", + "Dicts are defined by outer curly braces and comma-separated items. Items are colon-separated keys and values. Witness the following examples:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# A dictionary on one line that stores info about Einstein\n", + "al = {\"first\": \"Albert\", \"last\": \"Einstein\", \"birthday\": [1879, 3, 14]}\n", + "\n", + "# You can split up dicts onto many lines\n", + "constants = {\n", + " 'pi': 3.14159,\n", + " \"e\": 2.718,\n", + " \"h\": 6.62606957e-34,\n", + " True: 1.0,\n", + " }\n", + "\n", + "# A dict being formed from a list of (key, value) tuples\n", + "axes = dict([(1, \"x\"), (2, \"y\"), (3, \"z\")])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You pull a value out of a dictionary by indexing with the associated key, as follows:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "constants['e']" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "axes[3]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "al['birthday']" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Dictionaries cannot be sliced because they are unordered, but it is possible to add or delete values through indexing" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "constants[False] = 0.0\n", + "del axes[3]\n", + "al['first'] = \"You can call me Al\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Dicts are not hashable, so dictionaries cannot be keys in other dictionaries, but they can be values. This property allows for the infinitely recurring trick seen with lists earlier:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "d = {}\n", + "d['d'] = d\n", + "d" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "{} # empty dict\n", + "set() # empty set" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Test for containment with the in operator using a key, not a value:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "\"N_A\" in constants" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The update() method is a handy way to change dicts. It rewrites any keys that are overwritten by the update. More methods are available in chapters 5 and 6." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "axes.update({1: 'r', 2: 'phi', 3: 'theta'})\n", + "axes" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "axes.update({3: 'z'})\n", + "axes" + ] + } + ], "metadata": { - "name": "", - "signature": "sha256:800017843464a179d7c7dbd4b99b0406d1e5584623a77b58c76db4905b05af8b" - }, - "nbformat": 3, - "nbformat_minor": 0, - "worksheets": [ - { - "cells": [ - { - "cell_type": "code", - "collapsed": false, - "input": [ - "[6, 28]" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 1, - "text": [ - "[6, 28]" - ] - } - ], - "prompt_number": 1 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "[1e3, -2, \"I am in a list.\"]" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 2, - "text": [ - "[1000.0, -2, 'I am in a list.']" - ] - } - ], - "prompt_number": 2 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "[[1.0, 0.0], [0.0, 1.0]]" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 3, - "text": [ - "[[1.0, 0.0], [0.0, 1.0]]" - ] - } - ], - "prompt_number": 3 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "[1, 1] + [2, 3, 5] + [8]" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 4, - "text": [ - "[1, 1, 2, 3, 5, 8]" - ] - } - ], - "prompt_number": 4 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "fib = [1, 1, 2, 3, 5, 8]" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 5 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "fib.append(13)\n", - "fib" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 6, - "text": [ - "[1, 1, 2, 3, 5, 8, 13]" - ] - } - ], - "prompt_number": 6 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "fib.extend([21, 34, 55])\n", - "fib" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 7, - "text": [ - "[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]" - ] - } - ], - "prompt_number": 7 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "fib += [89, 144]\n", - "fib" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 8, - "text": [ - "[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144]" - ] - } - ], - "prompt_number": 8 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "fib[::2]" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 9, - "text": [ - "[1, 2, 5, 13, 34, 89]" - ] - } - ], - "prompt_number": 9 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "fib[3] = \"whoops\"\n", - "fib" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 10, - "text": [ - "[1, 1, 2, 'whoops', 5, 8, 13, 21, 34, 55, 89, 144]" - ] - } - ], - "prompt_number": 10 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "del fib[:5]\n", - "fib" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 11, - "text": [ - "[8, 13, 21, 34, 55, 89, 144]" - ] - } - ], - "prompt_number": 11 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "fib[1::2] = [-1, -1, -1] \n", - "fib " - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 12, - "text": [ - "[8, -1, 21, -1, 55, -1, 144]" - ] - } - ], - "prompt_number": 12 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "[1, 2, 3] * 6" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 13, - "text": [ - "[1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3]" - ] - } - ], - "prompt_number": 13 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "list(\"F = dp/dt\")" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 14, - "text": [ - "['F', ' ', '=', ' ', 'd', 'p', '/', 'd', 't']" - ] - } - ], - "prompt_number": 14 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "x = []\n", - "x.append(x)\n", - "x" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 15, - "text": [ - "[[...]]" - ] - } - ], - "prompt_number": 15 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "x[0]" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 16, - "text": [ - "[[...]]" - ] - } - ], - "prompt_number": 16 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "x[0][0]" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 17, - "text": [ - "[[...]]" - ] - } - ], - "prompt_number": 17 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "x = 42\n", - "y = x\n", - "del x" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 18 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "x = [3, 2, 1, \"blast off!\"]\n", - "y = x\n", - "y[1] = \"TWO\"\n", - "print(x)" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "[3, 'TWO', 1, 'blast off!']\n" - ] - } - ], - "prompt_number": 19 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "a = 1, 2, 5, 3 # length-4 tuple\n", - "b = (42,) # length-1 tuple, defined by comma\n", - "c = (42) # not a tuple, just the number 42\n", - "d = () # length-0 tuple- no commas means no elements" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 20 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "(1, 2) + (3, 4)" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 21, - "text": [ - "(1, 2, 3, 4)" - ] - } - ], - "prompt_number": 21 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "1, 2 + 3, 4" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 22, - "text": [ - "(1, 5, 4)" - ] - } - ], - "prompt_number": 22 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "tuple([\"e\", 2.718])" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 23, - "text": [ - "('e', 2.718)" - ] - } - ], - "prompt_number": 23 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "x = 1.0, [2, 4], 16\n", - "x[1].append(8)\n", - "x" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 24, - "text": [ - "(1.0, [2, 4, 8], 16)" - ] - } - ], - "prompt_number": 24 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "# a literal set formed with elements of various types\n", - "{1.0, 10, \"one hundred\", (1, 0, 0,0)}" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 25, - "text": [ - "{1.0, 10, (1, 0, 0, 0), 'one hundred'}" - ] - } - ], - "prompt_number": 25 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "# a literal set of special values\n", - "{True, False, None, \"\", 0.0, 0}" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 26, - "text": [ - "{0, '', None, True}" - ] - } - ], - "prompt_number": 26 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "# conversion from a list to a set\n", - "set([2.0, 4, \"eight\", (16,)])" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 27, - "text": [ - "{'eight', 2.0, (16,), 4}" - ] - } - ], - "prompt_number": 27 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "set(\"Marie Curie\")" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 28, - "text": [ - "{' ', 'C', 'M', 'a', 'e', 'i', 'r', 'u'}" - ] - } - ], - "prompt_number": 28 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "set([\"Marie Curie\"])" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 29, - "text": [ - "{'Marie Curie'}" - ] - } - ], - "prompt_number": 29 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "# A dictionary on one line that stores info about Einstein\n", - "al = {\"first\": \"Albert\", \"last\": \"Einstein\", \"birthday\": [1879, 3, 14]}\n", - "\n", - "# You can split up dicts onto many lines\n", - "constants = {\n", - " 'pi': 3.14159,\n", - " \"e\": 2.718,\n", - " \"h\": 6.62606957e-34,\n", - " True: 1.0,\n", - " }\n", - "\n", - "# A dict being formed from a list of (key, value) tuples\n", - "axes = dict([(1, \"x\"), (2, \"y\"), (3, \"z\")])" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 30 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "constants['e']" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 31, - "text": [ - "2.718" - ] - } - ], - "prompt_number": 31 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "axes[3]" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 32, - "text": [ - "'z'" - ] - } - ], - "prompt_number": 32 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "al['birthday']" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 33, - "text": [ - "[1879, 3, 14]" - ] - } - ], - "prompt_number": 33 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "constants[False] = 0.0\n", - "del axes[3]\n", - "al['first'] = \"You can call me Al\"" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 34 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "d = {}\n", - "d['d'] = d\n", - "d" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 35, - "text": [ - "{'d': {...}}" - ] - } - ], - "prompt_number": 35 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "{} # empty dict\n", - "set() # empty set" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 36, - "text": [ - "set()" - ] - } - ], - "prompt_number": 36 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "\"N_A\" in constants" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 37, - "text": [ - "False" - ] - } - ], - "prompt_number": 37 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "axes.update({1: 'r', 2: 'phi', 3: 'theta'})\n", - "axes" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 38, - "text": [ - "{1: 'r', 2: 'phi', 3: 'theta'}" - ] - } - ], - "prompt_number": 38 - } - ], - "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.6" } - ] -} \ No newline at end of file + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/ch04-flow-control.ipynb b/ch04-flow-control.ipynb index fd2b0d3..4783b42 100644 --- a/ch04-flow-control.ipynb +++ b/ch04-flow-control.ipynb @@ -1,824 +1,1142 @@ { - "metadata": { - "name": "", - "signature": "sha256:4a3794c3f0dc7ce109b49a321bf0fe1521fc8909260e613e229d74c8f61de195" - }, - "nbformat": 3, - "nbformat_minor": 0, - "worksheets": [ - { - "cells": [ - { - "cell_type": "code", - "collapsed": false, - "input": [ - "h_bar = 1.0\n", - "if h_bar == 1.0:\n", - " print(\"h-bar isn't really unity! Resetting...\")\n", - " h_bar = 1.05457173e-34" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "h-bar isn't really unity! Resetting...\n" - ] - } - ], - "prompt_number": 1 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "h_bar = 1\n", - "if h_bar == 1:\n", - " print(\"h-bar isn't really unity! Resetting...\")\n", - " h_bar = 1.05457173e-34\n", - "h = h_bar * 2 * 3.14159" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "h-bar isn't really unity! Resetting...\n" - ] - } - ], - "prompt_number": 2 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "1 == 1" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 3, - "text": [ - "True" - ] - } - ], - "prompt_number": 3 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "1 == 1.0" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 4, - "text": [ - "True" - ] - } - ], - "prompt_number": 4 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "1 is 1.0" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 5, - "text": [ - "False" - ] - } - ], - "prompt_number": 5 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "1 is 1" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 6, - "text": [ - "True" - ] - } - ], - "prompt_number": 6 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "10**10 == 10**10" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 7, - "text": [ - "True" - ] - } - ], - "prompt_number": 7 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "10**10 is 10**10" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 8, - "text": [ - "False" - ] - } - ], - "prompt_number": 8 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "None is None" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 9, - "text": [ - "True" - ] - } - ], - "prompt_number": 9 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "0 is None " - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 10, - "text": [ - "False" - ] - } - ], - "prompt_number": 10 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "0 == None " - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 11, - "text": [ - "False" - ] - } - ], - "prompt_number": 11 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "h_bar = 1.05457173e-34 if h_bar == 1.0 else h_bar" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 12 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "val = 0.0\n", - "1.0 / val" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "ename": "ZeroDivisionError", - "evalue": "float division by zero", - "output_type": "pyerr", - "traceback": [ - "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[1;31mZeroDivisionError\u001b[0m Traceback (most recent call last)", - "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[0mval\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;36m0.0\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 2\u001b[1;33m \u001b[1;36m1.0\u001b[0m \u001b[1;33m/\u001b[0m \u001b[0mval\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", - "\u001b[1;31mZeroDivisionError\u001b[0m: float division by zero" - ] - } - ], - "prompt_number": 13 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "try:\n", - " inv = 1.0 / val\n", - "except: \n", - " print(\"A bad value was submitted {0}, please try again\".format(val))" - ], - "language": "python", + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Flow Control" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This chapter is about flow control. Flow control is like arithmetic for computers." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#Conditionals are the simplest form of flow control. They are like the English sentence, \"If this is true, do a certain thing; Otherwise, do something else.\" First we will meet the shortest conditional, the if statement. If statements have two parts, the condition and the block. When the boolean of the condition is True, the block is executed. If the condition is False, the block is skipped. " + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "h-bar isn't really unity! Resetting...\n" + ] + } + ], + "source": [ + "h_bar = 1.0\n", + "if h_bar == 1.0:\n", + " print(\"h-bar isn't really unity! Resetting...\")\n", + " h_bar = 1.05457173e-34" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "There are many logical operators available in python. Many are listed in table 4-1. We have already used the equality operator (==), which returns True when both sides of the operator have the same value. There is also the inequality operator (!=), which does the opposite, as seen below:" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "correcting h-bar...\n", + "h_bar = 1.05457173e-34\n" + ] + } + ], + "source": [ + "h_bar = 1.0\n", + "if h_bar != 1.05457173e-34:\n", + " print('correcting h-bar...')\n", + " h_bar = 1.05457173e-34\n", + " print('h_bar = {0}'.format(h_bar))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Note that whitespace is more important in python than other languages. The block of the if statement must be indented, and to exit that block we stop indenting." + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "h-bar isn't really unity! Resetting...\n" + ] + } + ], + "source": [ + "h_bar = 1\n", + "if h_bar == 1:\n", + " print(\"h-bar isn't really unity! Resetting...\")\n", + " h_bar = 1.05457173e-34\n", + "h = h_bar * 2 * 3.14159" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The following examples emphasize the distinction between the equality operator (==) and the identity operator (is)." + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 28, "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "A bad value was submitted 0.0, please try again\n" - ] - } - ], - "prompt_number": 14 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "try:\n", - " inv = 1.0 / val\n", - "except ZeroDivisionError: \n", - " print(\"A zero value was submitted, please try again\")" - ], - "language": "python", + "output_type": "execute_result" + } + ], + "source": [ + "1 == 1" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 29, "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "A zero value was submitted, please try again\n" - ] - } - ], - "prompt_number": 15 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "try:\n", - " inv = 1.0 / val\n", - "except ZeroDivisionError: \n", - " print(\"A zero value was submitted, please try again\")\n", - "except: \n", - " print(\"A bad value was submitted {0}, please try again\".format(val))" - ], - "language": "python", + "output_type": "execute_result" + } + ], + "source": [ + "1 == 1.0" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "False" + ] + }, + "execution_count": 30, "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "A zero value was submitted, please try again\n" - ] - } - ], - "prompt_number": 16 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "if val == 0.0:\n", - " raise ZeroDivisionError\n", - "inv = 1.0 / val" - ], - "language": "python", + "output_type": "execute_result" + } + ], + "source": [ + "1 is 1.0" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 31, "metadata": {}, - "outputs": [ - { - "ename": "ZeroDivisionError", - "evalue": "", - "output_type": "pyerr", - "traceback": [ - "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[1;31mZeroDivisionError\u001b[0m Traceback (most recent call last)", - "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[1;32mif\u001b[0m \u001b[0mval\u001b[0m \u001b[1;33m==\u001b[0m \u001b[1;36m0.0\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 2\u001b[1;33m \u001b[1;32mraise\u001b[0m \u001b[0mZeroDivisionError\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 3\u001b[0m \u001b[0minv\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;36m1.0\u001b[0m \u001b[1;33m/\u001b[0m \u001b[0mval\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", - "\u001b[1;31mZeroDivisionError\u001b[0m: " - ] - } - ], - "prompt_number": 17 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "if val == 0.0:\n", - " raise ZeroDivisionError(\"taking the inverse of zero is forbidden!\")\n", - "inv = 1.0 / val" - ], - "language": "python", + "output_type": "execute_result" + } + ], + "source": [ + "1 is 1 # To help with performance, Python only stores a single copy of small integers" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 32, "metadata": {}, - "outputs": [ - { - "ename": "ZeroDivisionError", - "evalue": "taking the inverse of zero is forbidden!", - "output_type": "pyerr", - "traceback": [ - "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[1;31mZeroDivisionError\u001b[0m Traceback (most recent call last)", - "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[1;32mif\u001b[0m \u001b[0mval\u001b[0m \u001b[1;33m==\u001b[0m \u001b[1;36m0.0\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 2\u001b[1;33m \u001b[1;32mraise\u001b[0m \u001b[0mZeroDivisionError\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m\"taking the inverse of zero is forbidden!\"\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 3\u001b[0m \u001b[0minv\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;36m1.0\u001b[0m \u001b[1;33m/\u001b[0m \u001b[0mval\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", - "\u001b[1;31mZeroDivisionError\u001b[0m: taking the inverse of zero is forbidden!" - ] - } - ], - "prompt_number": 18 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "t = 3\n", - "while 0 < t:\n", - " print(\"t-minus \" + str(t))\n", - " t = t - 1\n", - "print(\"blastoff!\")" - ], - "language": "python", + "output_type": "execute_result" + } + ], + "source": [ + "10**10 == 10**10" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "False" + ] + }, + "execution_count": 33, "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "t-minus 3\n", - "t-minus 2\n", - "t-minus 1\n", - "blastoff!\n" - ] - } - ], - "prompt_number": 19 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "while False:\n", - " print(\"I am sorry, Dave.\")\n", - "print(\"I can't print that for you.\")" - ], - "language": "python", + "output_type": "execute_result" + } + ], + "source": [ + "10**10 is 10**10 # Larger integers are computed each time" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 34, "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "I can't print that for you.\n" - ] - } - ], - "prompt_number": 20 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "# Uncomment the following to print forever\n", - "#t = 3\n", - "#while True:\n", - "# print(\"t-minus \" + str(t))\n", - "# t = t - 1\n", - "#print(\"blastoff!\")" - ], - "language": "python", + "output_type": "execute_result" + } + ], + "source": [ + "None is None" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "False" + ] + }, + "execution_count": 35, "metadata": {}, - "outputs": [], - "prompt_number": 21 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "fib = [1, 1]\n", - "while True:\n", - " x = fib[-2] + fib[-1]\n", - " if x%12 == 0:\n", - " break\n", - " fib.append(x)" - ], - "language": "python", + "output_type": "execute_result" + } + ], + "source": [ + "0 is None # Only None is None" + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "False" + ] + }, + "execution_count": 36, "metadata": {}, - "outputs": [], - "prompt_number": 22 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "for t in [3, 2, 1]:\n", - " print(\"t-minus \" + str(t))\n", - "print(\"blastoff!\")" - ], - "language": "python", + "output_type": "execute_result" + } + ], + "source": [ + "0 == None " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### If-else statements" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "By adding the word else and and else-block, you are telling python what to do when the if-statement is False. A few examples follow:" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0.5944807685248221" + ] + }, + "execution_count": 37, "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "t-minus 3\n", - "t-minus 2\n", - "t-minus 1\n", - "blastoff!\n" - ] - } - ], - "prompt_number": 23 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "for t in [7, 6, 5, 4, 3, 2, 1]:\n", - " if t%2 == 0:\n", - " continue\n", - " print(\"t-minus \" + str(t))\n", - "print(\"blastoff!\")" - ], - "language": "python", + "output_type": "execute_result" + } + ], + "source": [ + "import math as math #imports the math module so we can use the sine function. See chapter 2 for more on modules\n", + "\n", + "x = math.pi / 2 \n", + "\n", + "if x == 0:\n", + " y = 0\n", + "else:\n", + " y = math.sin(1/x)\n", + "\n", + "y" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "$Sin(\\frac{1}{x})$ cannot be easily computed if x = 0, but L'Hopital's rule tells us this function is zero at the origin, so an if statement is helpful in computing $Sin(\\frac{1}{x})$, as shown above and below. The first cell uses the == operator, while the second uses the != operator. Because the if-block and else-block are switched in these two cells, they have the same behavior. However, it is generally best practice to use positive operators than negative ones, as it eases debugging by simplifying the logic." + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0.9560556573276295" + ] + }, + "execution_count": 38, "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "t-minus 7\n", - "t-minus 5\n", - "t-minus 3\n", - "t-minus 1\n", - "blastoff!\n" - ] - } - ], - "prompt_number": 24 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "for letter in \"Gorgus\":\n", - " print(letter)" - ], - "language": "python", + "output_type": "execute_result" + } + ], + "source": [ + "import math as math #imports the math module so we can use the sine function. See chapter 2 for more on modules\n", + "\n", + "x = math.pi / 4\n", + "\n", + "if x != 0:\n", + " y = math.sin(1/x)\n", + "else:\n", + " y = 0\n", + "\n", + "y" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "There are also if-elif-else statements. The elif-statement is the similar to the if-statement. Each condition is evaluated in the order they are written, and the first one to return True has its block exectued. The others are skipped. If none of the conditions are True, then the else block is evaluated. Observe:" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "1.0" + ] + }, + "execution_count": 39, "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "G\n", - "o\n", - "r\n", - "g\n", - "u\n", - "s\n" - ] - } - ], - "prompt_number": 25 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "for x in {\"Gorgus\", 0, True}:\n", - " print(x)" - ], - "language": "python", + "output_type": "execute_result" + } + ], + "source": [ + "omega = 3.6\n", + "\n", + "if omega < 1.0:\n", + " signal = 0.0\n", + "elif omega > 10.0:\n", + " signal = 0.0\n", + "else:\n", + " signal = 1.0\n", + "\n", + "signal" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "if-else statements can be done in one line, which is often convenient." + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "1.05457173e-34" + ] + }, + "execution_count": 40, "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "0\n", - "True\n", - "Gorgus\n" - ] - } - ], - "prompt_number": 26 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "d = {\"first\": \"Albert\", \n", - " \"last\": \"Einstein\", \n", - " \"birthday\": [1879, 3, 14]}\n", - "\n", - "for key in d:\n", - " print(key)\n", - " print(d[key])\n", - " print(\"======\")" - ], - "language": "python", + "output_type": "execute_result" + } + ], + "source": [ + "h_bar = 1\n", + "h_bar = 1.05457173e-34 if h_bar == 1.0 else h_bar\n", + "h_bar" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exceptions \n", + "Exceptions help us navigate around errors that otherwise cannot be avoided, such as when the user inputs an impossible value. Consider the following example:" + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "ename": "ZeroDivisionError", + "evalue": "float 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[1;32m 1\u001b[0m \u001b[0mval\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;36m0.0\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0;36m1.0\u001b[0m \u001b[0;34m/\u001b[0m \u001b[0mval\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;31mZeroDivisionError\u001b[0m: float division by zero" + ] + } + ], + "source": [ + "val = 0.0\n", + "1.0 / val " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This situation can be avoided by adding a try-except block. These blocks look somewhat similar to if-else blocks, but do not contain conditions. First the code that follows Try: is executed. If any error is encountered, the code following Except: is executed. If there are no errors, the Except-block is skipped. It is generally advisable to write short (ideally one-line) Try-blocks. See the following example." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " inv = 1.0 / val\n", + "except: \n", + " print(\"A bad value was submitted {0}, please try again\".format(val))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can also put the name of an error after except, allowing for a more specific behavior" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " inv = 1.0 / val\n", + "except ZeroDivisionError: \n", + " print(\"A zero value was submitted, please try again\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "There is also the option to put multiple Except blocks, similar to elif. The first exception encountered will be executed." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " inv = 1.0 / val\n", + "except ZeroDivisionError: \n", + " print(\"A zero value was submitted, please try again\")\n", + "except: \n", + " print(\"A bad value was submitted {0}, please try again\".format(val))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can also use the raise keyword, which throws an exception that may be caught by a try-except block later on. The raise keyword standardizes the code's response to an unallowed situation. Typically they are placed inside conditionals so they are not run unnecessarily." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "if val == 0.0:\n", + " raise ZeroDivisionError\n", + "inv = 1.0 / val" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "if val == 0.0:\n", + " raise ZeroDivisionError(\"taking the inverse of zero is forbidden!\")\n", + "inv = 1.0 / val" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Loops" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Loops allow the computer to repeat a task. We will discuss while loops, for loops, and comprehensions." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### While loops" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The first loop discussed is the while loop. In this loop, a condition is provided. If the condition met is true, the code block will be executed. When the execution is complete, the condition is evaluated again, and the code is re-executed until the condition is no longer true. Observe:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "t = 3\n", + "while 0 < t:\n", + " print(\"t-minus \" + str(t))\n", + " t = t - 1\n", + "print(\"blastoff!\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If the condition is false, the block will never run" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "while False:\n", + " print(\"I am sorry, Dave.\")\n", + "print(\"I can't print that for you.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If the condition is never false, the loop never stops. This behavior is almost never desired. Such a loop is called an infinite or nonterminating loop. Observe what happens when the countdown loop from before is modified slightly:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Uncomment the following to print forever\n", + "#t = 3\n", + "#while True:\n", + "# print(\"t-minus \" + str(t))\n", + "# t = t - 1\n", + "#print(\"blastoff!\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Uncomment the following to print forever a different way\n", + "# t = 3\n", + "# while t == 3:\n", + "# print(\"t-minus \" + str(t))\n", + "# print(\"blastoff!\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If you ever accidentally write a nonterminating loop, hit ctrl-c in your terminal to stop it." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The break statement is used to interrupt a loop. Observe:" + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]" + ] + }, + "execution_count": 44, "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "birthday\n", - "[1879, 3, 14]\n", - "======\n", - "last\n", - "Einstein\n", - "======\n", - "first\n", - "Albert\n", - "======\n" - ] - } - ], - "prompt_number": 27 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "d = {\"first\": \"Albert\", \n", - " \"last\": \"Einstein\", \n", - " \"birthday\": [1879, 3, 14]}\n", - "\n", - "print(\"Keys:\")\n", - "for key in d.keys():\n", - " print(key)\n", + "output_type": "execute_result" + } + ], + "source": [ + "fib = [1, 1]\n", + "\n", + "while True:\n", + " x = fib[-2] + fib[-1]\n", + " if x % 12 == 0:\n", + " break\n", + " fib.append(x)\n", + "\n", + "fib" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### For Loops" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "An alternative to while loops is the for loop, which evaluates an expression while iterating through a containter. Consider the following example, in which a short list is used as an iterable:" + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "t-minus 3\n", + "t-minus 2\n", + "t-minus 1\n", + "blastoff!\n" + ] + } + ], + "source": [ + "for t in [3, 2, 1]:\n", + " print(\"t-minus \" + str(t))\n", + "print(\"blastoff!\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The break statement works just the same in a for loop as in a while loop. Additionally, the continue statement may be used to skip over one interation of the loop and continue with the next. Continue may also be used in a while loop. The following code uses Continue to only print the odd numbers in a list." + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "t-minus 7\n", + "t-minus 5\n", + "t-minus 3\n", + "t-minus 1\n", + "blastoff!\n" + ] + } + ], + "source": [ + "for t in [7, 6, 5, 4, 3, 2, 1]:\n", + " if t%2 == 0:\n", + " continue\n", + " print(\"t-minus \" + str(t))\n", + "print(\"blastoff!\")" + ] + }, + { + "cell_type": "code", + "execution_count": 54, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "G\n", + "o\n", + "r\n", + "g\n", + "u\n", + "s\n" + ] + } + ], + "source": [ + "for letter in \"Gorgus\":\n", + " print(letter)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Unordered data containers like dicts and sets can be troublesome as iterators because their order is unpredictable. Observe: " + ] + }, + { + "cell_type": "code", + "execution_count": 56, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0\n", + "True\n", + "Gorgus\n" + ] + } + ], + "source": [ + "for x in {\"Gorgus\", 0, True}:\n", + " print(x)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The next cell demonstrates the use of a dictionary as an iterable. Python assumes that the key is what is being iterated. Each item in the dict can be listed with code like the following:" + ] + }, + { + "cell_type": "code", + "execution_count": 58, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "first\n", + "Albert\n", + "======\n", + "last\n", + "Einstein\n", + "======\n", + "birthday\n", + "[1879, 3, 14]\n", + "======\n" + ] + } + ], + "source": [ + "d = {\"first\": \"Albert\", \n", + " \"last\": \"Einstein\", \n", + " \"birthday\": [1879, 3, 14]}\n", + "\n", + "for key in d:\n", + " print(key)\n", + " print(d[key])\n", + " print(\"======\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Dictionaries may also be explicitly looped through their keys, values, or items using the keys() , values() , or items() methods:" + ] + }, + { + "cell_type": "code", + "execution_count": 60, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Keys:\n", + "first\n", + "last\n", + "birthday\n", "\n", - "print(\"\\n======\\n\")\n", + "======\n", "\n", - "print(\"Values:\")\n", - "for value in d.values():\n", - " print(value)\n", + "Values:\n", + "Albert\n", + "Einstein\n", + "[1879, 3, 14]\n", "\n", - "print(\"\\n======\\n\")\n", + "======\n", "\n", - "print(\"Items:\")\n", - "for key, value in d.items():\n", - " print(key, value)" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "Keys:\n", - "birthday\n", - "last\n", - "first\n", - "\n", - "======\n", - "\n", - "Values:\n", - "[1879, 3, 14]\n", - "Einstein\n", - "Albert\n", - "\n", - "======\n", - "\n", - "Items:\n", - "birthday [1879, 3, 14]\n", - "last Einstein\n", - "first Albert\n" - ] - } - ], - "prompt_number": 28 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "for item in d.items():\n", - " print(item)" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "('birthday', [1879, 3, 14])\n", - "('last', 'Einstein')\n", - "('first', 'Albert')\n" - ] - } - ], - "prompt_number": 29 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "quarks = {'up', 'down', 'top', 'bottom', 'charm', 'strange'}\n", - "for quark in quarks:\n", - " print(quark)" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "bottom\n", - "down\n", - "up\n", - "strange\n", - "top\n", - "charm\n" - ] - } - ], - "prompt_number": 30 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "upper_quarks = []\n", - "for quark in quarks:\n", - " upper_quarks.append(quark.upper())" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 31 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "upper_quarks = [quark.upper() for quark in quarks]\n", - "upper_quarks" - ], - "language": "python", + "Items:\n", + "first Albert\n", + "last Einstein\n", + "birthday [1879, 3, 14]\n" + ] + } + ], + "source": [ + "d = {\"first\": \"Albert\", \n", + " \"last\": \"Einstein\", \n", + " \"birthday\": [1879, 3, 14]}\n", + "\n", + "print(\"Keys:\")\n", + "for key in d.keys():\n", + " print(key)\n", + "\n", + "print(\"\\n======\\n\")\n", + "\n", + "print(\"Values:\")\n", + "for value in d.values():\n", + " print(value)\n", + "\n", + "print(\"\\n======\\n\")\n", + "\n", + "print(\"Items:\")\n", + "for key, value in d.items():\n", + " print(key, value)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Notice that the items are tuples. We have chosen to explicitly unpack them in the preceding code, but this is not necessary. See below:" + ] + }, + { + "cell_type": "code", + "execution_count": 63, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "('first', 'Albert')\n", + "('last', 'Einstein')\n", + "('birthday', [1879, 3, 14])\n" + ] + } + ], + "source": [ + "for item in d.items():\n", + " print(item)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Comprehension" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Comprehension allow us to run simple for loops in a single line. The following two cells are a verbose way of printing the elements in a set. The same output can be produced from a single line using a comprehension." + ] + }, + { + "cell_type": "code", + "execution_count": 62, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "charm\n", + "top\n", + "down\n", + "up\n", + "bottom\n", + "strange\n" + ] + } + ], + "source": [ + "quarks = {'up', 'down', 'top', 'bottom', 'charm', 'strange'}\n", + "for quark in quarks:\n", + " print(quark)" + ] + }, + { + "cell_type": "code", + "execution_count": 69, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['CHARM', 'TOP', 'STRANGE']\n" + ] + } + ], + "source": [ + "upper_quarks = []\n", + "for quark in quarks:\n", + " upper_quarks.append(quark.upper())\n", + "\n", + "print(upper_quarks)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Here comes a comprehension that does the same thing as the previous for loop with $\\frac{1}{3}$ the number of lines:" + ] + }, + { + "cell_type": "code", + "execution_count": 71, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['CHARM', 'TOP', 'STRANGE']" + ] + }, + "execution_count": 71, "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 32, - "text": [ - "['BOTTOM', 'DOWN', 'UP', 'STRANGE', 'TOP', 'CHARM']" - ] - } - ], - "prompt_number": 32 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "entries = ['top', 'CHARm', 'Top', 'sTraNGe', 'strangE', 'top']\n", - "quarks = {quark.lower() for quark in entries}\n", - "quarks" - ], - "language": "python", + "output_type": "execute_result" + } + ], + "source": [ + "upper_quarks = [quark.upper() for quark in quarks]\n", + "upper_quarks" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "A comprehension can also be used to output a set. The following cell uses a set to ignore misspellings of repeated words:" + ] + }, + { + "cell_type": "code", + "execution_count": 76, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'charm', 'strange', 'top'}" + ] + }, + "execution_count": 76, "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 33, - "text": [ - "{'charm', 'strange', 'top'}" - ] - } - ], - "prompt_number": 33 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "entries = [1, 10, 12.5, 65, 88]\n", - "results = {x: x**2 + 42 for x in entries}\n", - "results" - ], - "language": "python", + "output_type": "execute_result" + } + ], + "source": [ + "entries = ['top', 'CHARm', 'Top', 'sTraNGe', 'strangE', 'top']\n", + "quarks = {quark.lower() for quark in entries}\n", + "quarks" + ] + }, + { + "cell_type": "raw", + "metadata": {}, + "source": [ + "Here comes a cell that shows us how to make a dictionary with the inputs and outputs as keys and values. This kind of comprehension is ideal for iterating through a list while maintaining a mapping between the inputs and outputs." + ] + }, + { + "cell_type": "code", + "execution_count": 77, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{1: 43, 10: 142, 12.5: 198.25, 65: 4267, 88: 7786}" + ] + }, + "execution_count": 77, "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 34, - "text": [ - "{88: 7786, 1: 43, 10: 142, 12.5: 198.25, 65: 4267}" - ] - } - ], - "prompt_number": 34 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "{x**2 for x in fib if x%5 == 0}" - ], - "language": "python", + "output_type": "execute_result" + } + ], + "source": [ + "entries = [1, 10, 12.5, 65, 88]\n", + "results = {x: x**2 + 42 for x in entries}\n", + "results" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Comprehensions may also use filters, which allow us to supply a condition such that the loop will evaluate its block if the condition is True, and skip and iterations for which the condition is False. Filters use the if keyword. The following cell uses this syntax to fins the squares of fibonacci numbers that are divisible by 5:" + ] + }, + { + "cell_type": "code", + "execution_count": 82, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{25, 3025}" + ] + }, + "execution_count": 82, "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 35, - "text": [ - "{25, 3025}" - ] - } - ], - "prompt_number": 35 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "coords = {'x': 1, 'y': 2, 'z': 3, 'r': 1, 'theta': 2, 'phi': 3}\n", - "polar_keys = {'r', 'theta', 'phi'}\n", - "polar = {key: value for key, value in coords.items() if key in polar_keys}\n", - "polar" - ], - "language": "python", + "output_type": "execute_result" + } + ], + "source": [ + "{x**2 for x in fib if x%5 == 0}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "A filtered comprehension may also be used to create a new dictionary that is a subset of a larger dictionary:" + ] + }, + { + "cell_type": "code", + "execution_count": 83, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'phi': 3, 'r': 1, 'theta': 2}" + ] + }, + "execution_count": 83, "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 36, - "text": [ - "{'r': 1, 'theta': 2, 'phi': 3}" - ] - } - ], - "prompt_number": 36 - } - ], - "metadata": {} + "output_type": "execute_result" + } + ], + "source": [ + "coords = {'x': 1, 'y': 2, 'z': 3, 'r': 1, 'theta': 2, 'phi': 3}\n", + "polar_keys = {'r', 'theta', 'phi'}\n", + "polar = {key: value for key, value in coords.items() if key in polar_keys}\n", + "polar" + ] } - ] -} \ No newline at end of file + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/ch05-functions.ipynb b/ch05-functions.ipynb index cc377d9..6fc0c43 100644 --- a/ch05-functions.ipynb +++ b/ch05-functions.ipynb @@ -1,1497 +1,1468 @@ { - "metadata": { - "name": "", - "signature": "sha256:d5c640256cbcd5acf07a453deb6083fcadd0d02cc13af07503bdbb0472cd267d" - }, - "nbformat": 3, - "nbformat_minor": 0, - "worksheets": [ + "cells": [ { - "cells": [ - { - "cell_type": "code", - "collapsed": false, - "input": [ - "def sagan():\n", - " quote = \"With insufficient data it is easy to go wrong.\"" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 1 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "def null():\n", - " pass" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 2 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "# define the function\n", - "def forty_two():\n", - " return 42" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 3 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "# call the function\n", - "forty_two()" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 4, - "text": [ - "42" - ] - } - ], - "prompt_number": 4 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "# call the function, and print the result\n", - "print(forty_two())" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "42\n" - ] - } - ], - "prompt_number": 5 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "# call the function, assign the result \n", - "# to x, and print x\n", - "x = forty_two()\n", - "print(x)" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "42\n" - ] - } - ], - "prompt_number": 6 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "def forty_two_or_bust(x):\n", - " if x:\n", - " print(42)\n", - " else:\n", - " print(0)" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 7 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "# call the function\n", - "forty_two_or_bust(True)" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "42\n" - ] - } - ], - "prompt_number": 8 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "bust = False\n", - "forty_two_or_bust(bust)" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "0\n" - ] - } - ], - "prompt_number": 9 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "def power(base, x):\n", - " return base**x" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 10 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "from math import sin\n", - "\n", - "def sin_inv_x(x):\n", - " if x == 0.0:\n", - " result = 0.0\n", - " else:\n", - " result = sin(1.0/x)\n", - " return result" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 11 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "def power(base, x):\n", - " \"\"\"Computes base^x. Both base and x should be integers,\n", - " floats, or another numeric type.\n", - " \"\"\"\n", - " return base**x" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 12 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "def line(x, a=1.0, b=0.0):\n", - " return a*x + b" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 13 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "line(42) # no keyword args, returns 1*42 + 0" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 14, - "text": [ - "42.0" - ] - } - ], - "prompt_number": 14 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "line(42, 2) # a=2, returns 84" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 15, - "text": [ - "84.0" - ] - } - ], - "prompt_number": 15 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "line(42, b=10) # b=10, returns 52" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 16, - "text": [ - "52.0" - ] - } - ], - "prompt_number": 16 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "line(42, b=10, a=2) # returns 94 " - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 17, - "text": [ - "94" - ] - } - ], - "prompt_number": 17 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "line(42, a=2, b=10) # also returns 94 " - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 18, - "text": [ - "94" - ] - } - ], - "prompt_number": 18 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "# Do not do this!\n", - "def myappend(x, lyst=[]):\n", - " lyst.append(x)\n", - " return lyst" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 19 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "myappend(6) # seems right" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 20, - "text": [ - "[6]" - ] - } - ], - "prompt_number": 20 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "myappend(42) # hmmm..." - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 21, - "text": [ - "[6, 42]" - ] - } - ], - "prompt_number": 21 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "myappend(12, [1, 16])" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 22, - "text": [ - "[1, 16, 12]" - ] - } - ], - "prompt_number": 22 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "myappend(65) # nope, not right!" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 23, - "text": [ - "[6, 42, 65]" - ] - } - ], - "prompt_number": 23 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "def myappend(x, lyst=None):\n", - " if lyst is None:\n", - " lyst = []\n", - " lyst.append(x)\n", - " return lyst" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 24 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "myappend(6) " - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 25, - "text": [ - "[6]" - ] - } - ], - "prompt_number": 25 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "myappend(42)" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 26, - "text": [ - "[42]" - ] - } - ], - "prompt_number": 26 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "myappend(12, [1, 16])" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 27, - "text": [ - "[1, 16, 12]" - ] - } - ], - "prompt_number": 27 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "myappend(65)" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 28, - "text": [ - "[65]" - ] - } - ], - "prompt_number": 28 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "max(6, 2)" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 29, - "text": [ - "6" - ] - } - ], - "prompt_number": 29 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "max(6, 42)" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 30, - "text": [ - "42" - ] - } - ], - "prompt_number": 30 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "max(1, 16, 12)" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 31, - "text": [ - "16" - ] - } - ], - "prompt_number": 31 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "max(65, 42, 2, 8)" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 32, - "text": [ - "65" - ] - } - ], - "prompt_number": 32 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "def minimum(*args):\n", - " \"\"\"Takes any number of arguments!\"\"\"\n", - " m = args[0]\n", - " for x in args[1:]:\n", - " if x < m:\n", - " m = x\n", - " return m " - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 33 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "minimum(6, 42)" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 34, - "text": [ - "6" - ] - } - ], - "prompt_number": 34 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "data = [65, 42, 2, 8]\n", - "minimum(*data)" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 35, - "text": [ - "2" - ] - } - ], - "prompt_number": 35 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "def blender(*args, **kwargs):\n", - " \"\"\"Will it?\"\"\"\n", - " print(args, kwargs)" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 36 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "blender(\"yes\", 42)" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "('yes', 42) {}\n" - ] - } - ], - "prompt_number": 37 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "blender(z=6, x=42)" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "() {'z': 6, 'x': 42}\n" - ] - } - ], - "prompt_number": 38 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "blender(\"no\", [1], \"yes\", z=6, x=42)" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "('no', [1], 'yes') {'z': 6, 'x': 42}\n" - ] - } - ], - "prompt_number": 39 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "t = (\"no\",)\n", - "d = {\"mom\": \"ionic\"}\n", - "blender(\"yes\", kid=\"covalent\", *t, **d)" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "('yes', 'no') {'mom': 'ionic', 'kid': 'covalent'}\n" - ] - } - ], - "prompt_number": 40 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "def momentum_energy(m, v):\n", - " p = m * v\n", - " e = 0.5 * m * v**2\n", - " return p, e" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 41 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "# returns a tuple\n", - "p_e = momentum_energy(42.0, 65.0)\n", - "print(p_e)" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "(2730.0, 88725.0)\n" - ] - } - ], - "prompt_number": 42 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "# unpacks the tuple\n", - "mom, eng = momentum_energy(42.0, 65.0)\n", - "print(mom)" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "2730.0\n" - ] - } - ], - "prompt_number": 43 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "# global scope\n", - "a = 6\n", - "b = 42\n", - "\n", - "def func(x, y):\n", - " # local scope\n", - " z = 16\n", - " return a*x + b*y + z\n", - "\n", - "# global scope\n", - "c = func(1, 5)" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 44 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "# global scope\n", - "a = 6\n", - "b = 42\n", - "\n", - "def outer(m, n):\n", - " # outer's scope\n", - " p = 10 \n", - "\n", - " def inner(x, y):\n", - " # inner's scope\n", - " return a*p*x + b*n*y\n", - "\n", - " # outer's scope\n", - " return inner(m+1, n+1)\n", - "\n", - "# global scope\n", - "c = outer(1, 5)" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 45 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "a = 6\n", - "\n", - "def a_global():\n", - " print(a)\n", - "\n", - "def a_local():\n", - " a = 42\n", - " print(a)\n", - "\n", - "a_global()\n", - "a_local()\n", - "print(a)" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "6\n", - "42\n", - "6\n" - ] - } - ], - "prompt_number": 46 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "a = \"A\"\n", - "\n", - "def func():\n", - " # you cannot use the global 'a' because...\n", - " print(\"Big \" + a)\n", - " # a local 'a' is eventually defined!\n", - " a = \"a\"\n", - " print(\"small \" + a)\n", - "\n", - "func()" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "ename": "UnboundLocalError", - "evalue": "local variable 'a' referenced before assignment", - "output_type": "pyerr", - "traceback": [ - "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[1;31mUnboundLocalError\u001b[0m Traceback (most recent call last)", - "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[0;32m 8\u001b[0m \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m\"small \"\u001b[0m \u001b[1;33m+\u001b[0m \u001b[0ma\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 9\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 10\u001b[1;33m \u001b[0mfunc\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", - "\u001b[1;32m\u001b[0m in \u001b[0;36mfunc\u001b[1;34m()\u001b[0m\n\u001b[0;32m 3\u001b[0m \u001b[1;32mdef\u001b[0m \u001b[0mfunc\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 4\u001b[0m \u001b[1;31m# you cannot use the global 'a' because...\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 5\u001b[1;33m \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m\"Big \"\u001b[0m \u001b[1;33m+\u001b[0m \u001b[0ma\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 6\u001b[0m \u001b[1;31m# a local 'a' is eventually defined!\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 7\u001b[0m \u001b[0ma\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;34m\"a\"\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", - "\u001b[1;31mUnboundLocalError\u001b[0m: local variable 'a' referenced before assignment" - ] - } - ], - "prompt_number": 47 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "a = \"A\"\n", - "\n", - "def func():\n", - " global a\n", - " print(\"Big \" + a)\n", - " a = \"a\"\n", - " print(\"small \" + a)\n", - "\n", - "func()\n", - "print(\"global \" + a)" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "Big A\n", - "small a\n", - "global a\n" - ] - } - ], - "prompt_number": 48 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "# DO NOT RUN THIS\n", - "#def func():\n", - "# func()" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 49 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "def fib(n):\n", - " if n == 0 or n == 1:\n", - " return n\n", - " else:\n", - " return fib(n - 1) + fib(n - 2)" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 50 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "import sys\n", - "sys.getrecursionlimit() # return the current limit\n", - "sys.setrecursionlimit(8128) # change the limit to 8128" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 51 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "# a simple lambda\n", - "lambda x: x**2" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 52, - "text": [ - ">" - ] - } - ], - "prompt_number": 52 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "# a lambda that is called after it is defined\n", - "(lambda x, y=10: 2*x + y)(42)" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 53, - "text": [ - "94" - ] - } - ], - "prompt_number": 53 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "# just because it is anonymous doesn't mean we can't give it a name!\n", - "f = lambda: [x**2 for x in range(10)]\n", - "f()" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 54, - "text": [ - "[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]" - ] - } - ], - "prompt_number": 54 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "# a lambda as a dict value\n", - "d = {'null': lambda *args, **kwargs: None}" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 55 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "# a lambda as a keyword argument f in another function\n", - "def func(vals, f=lambda x: sum(x)/len(x)):\n", - " f(vals)" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 56 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "# a lambda as a keyword argument in a function call\n", - "func([6, 28, 496, 8128], lambda data: sum([x**2 for x in data]))" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 57 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "nums = [8128, 6, 496, 28]" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 58 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "sorted(nums)" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 59, - "text": [ - "[6, 28, 496, 8128]" - ] - } - ], - "prompt_number": 59 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "sorted(nums, key=lambda x: x%13)" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 60, - "text": [ - "[496, 28, 8128, 6]" - ] - } - ], - "prompt_number": 60 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "def countdown():\n", - " yield 3\n", - " yield 2\n", - " yield 1\n", - " yield 'Blast off!'" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 61 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "# generator\n", - "g = countdown()" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 62 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "next(g)" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 63, - "text": [ - "3" - ] - } - ], - "prompt_number": 63 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "x = next(g)\n", - "print(x)" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "2\n" - ] - } - ], - "prompt_number": 64 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "y, z = next(g), next(g)\n", - "print(z)" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "Blast off!\n" - ] - } - ], - "prompt_number": 65 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "next(g)" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "ename": "StopIteration", - "evalue": "", - "output_type": "pyerr", - "traceback": [ - "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[1;31mStopIteration\u001b[0m Traceback (most recent call last)", - "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[0mnext\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mg\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", - "\u001b[1;31mStopIteration\u001b[0m: " - ] - } - ], - "prompt_number": 66 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "for t in countdown():\n", - " if isinstance(t, int):\n", - " message = \"T-\" + str(t)\n", - " else:\n", - " message = t\n", - " print(message)" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "T-3\n", - "T-2\n", - "T-1\n", - "Blast off!\n" - ] - } - ], - "prompt_number": 67 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "def square_plus_one(n):\n", - " for x in range(n):\n", - " x2 = x * x\n", - " yield x2 + 1" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 68 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "for sp1 in square_plus_one(3):\n", - " print(sp1)" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "1\n", - "2\n", - "5\n" - ] - } - ], - "prompt_number": 69 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "# define a subgenerator\n", - "def yield_all(x):\n", - " for i in x:\n", - " yield i\n", - "\n", - "# palindrome using yield froms\n", - "def palindromize(x):\n", - " yield from yield_all(x)\n", - " yield from yield_all(x[::-1])\n", - "\n", - "# the above is equivalent to this full expansion:\n", - "def palindromize_explicit(x):\n", - " for i in x:\n", - " yield i\n", - " for i in x[::-1]:\n", - " yield i" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 70 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "def null(f):\n", - " \"\"\"Always return None.\"\"\"\n", - " return\n", - "\n", - "def identity(f):\n", - " \"\"\"Return the function.\"\"\"\n", - " return f\n", - "\n", - "def self_referential(f):\n", - " \"\"\"Return the decorator.\"\"\"\n", - " return self_referential" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 71 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "@null\n", - "def nargs(*args, **kwargs):\n", - " return len(args) + len(kwargs)" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 72 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "def nargs(*args, **kwargs):\n", - " return len(args) + len(kwargs)\n", - "nargs = null(nargs)" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 73 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "def plus1(f):\n", - " def wrapper(*args, **kwargs):\n", - " return f(*args, **kwargs) + 1\n", - " return wrapper" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 74 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "@plus1\n", - "def power(base, x):\n", - " return base**x\n", - "\n", - "power(4, 2)" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 75, - "text": [ - "17" - ] - } - ], - "prompt_number": 75 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "@plus1\n", - "@identity\n", - "@plus1\n", - "@plus1\n", - "def root(x):\n", - " return x**0.5\n", - "\n", - "root(4)" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 76, - "text": [ - "5.0" - ] - } - ], - "prompt_number": 76 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "def plus_n(n):\n", - " def dec(f):\n", - " def wrapper(*args, **kwargs):\n", - " return f(*args, **kwargs) + n\n", - " return wrapper\n", - " return dec" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 77 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "@plus_n(6)\n", - "def root(x):\n", - " return x**0.5\n", - "\n", - "root(4)" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 78, - "text": [ - "8.0" - ] - } - ], - "prompt_number": 78 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "max = plus1(max)" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 79 + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Functions" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This chapter will serve as the introduction to functions, the most basic form of code reuse in python. Functions in this context are very similar to functions in the mathematical context" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Functions in python" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's start by learning to define a function. The syntax is similar to the control statements explored in the previous chapter. A function has a name and a body. Optionally, it may have arguments and/or variables to return. The general syntax is below, followed by some simple examples" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + " def ([arguments]):\n", + " \n", + " [return]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Here is a function that creates a string and assigns it to a variable:" + ] + }, + { + "cell_type": "code", + "execution_count": 57, + "metadata": {}, + "outputs": [], + "source": [ + "def sagan():\n", + " quote = \"With insufficient data it is easy to go wrong.\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Here is a function that does nothing:" + ] + }, + { + "cell_type": "code", + "execution_count": 54, + "metadata": {}, + "outputs": [], + "source": [ + "def null():\n", + " pass" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The next couple of cells create and play with a function that takes no arguments and returns an integer." + ] + }, + { + "cell_type": "code", + "execution_count": 58, + "metadata": {}, + "outputs": [], + "source": [ + "# define the function\n", + "def forty_two():\n", + " return 42" + ] + }, + { + "cell_type": "code", + "execution_count": 59, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "42" + ] + }, + "execution_count": 59, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# call the function\n", + "forty_two()" + ] + }, + { + "cell_type": "code", + "execution_count": 60, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "42\n" + ] + } + ], + "source": [ + "# call the function, and print the result\n", + "print(forty_two())" + ] + }, + { + "cell_type": "code", + "execution_count": 62, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "42\n" + ] + } + ], + "source": [ + "# call the function, assign the result \n", + "# to x, and print x\n", + "x = forty_two()\n", + "print(x)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This function has an argument x. Its behavior depends on the value of x:" + ] + }, + { + "cell_type": "code", + "execution_count": 63, + "metadata": {}, + "outputs": [], + "source": [ + "def forty_two_or_bust(x):\n", + " if x:\n", + " print(42)\n", + " else:\n", + " print(0)" + ] + }, + { + "cell_type": "code", + "execution_count": 64, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "42\n" + ] + } + ], + "source": [ + "# call the function\n", + "forty_two_or_bust(True)" + ] + }, + { + "cell_type": "code", + "execution_count": 66, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0\n" + ] + } + ], + "source": [ + "bust = False\n", + "forty_two_or_bust(bust)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This function has two arguments, base and x. It returns base to the power of x." + ] + }, + { + "cell_type": "code", + "execution_count": 70, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "25\n", + "32\n" + ] + } + ], + "source": [ + "def power(base, x):\n", + " return base**x\n", + "print(power(5, 2))\n", + "print(power(2, 5))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This function should should remind you of an exercise from the previous chapter. It also calls a function inside of itself. Nesting functions is very powerful." + ] + }, + { + "cell_type": "code", + "execution_count": 73, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0.0\n", + "0.31296179620778664\n" + ] + } + ], + "source": [ + "from math import sin # Review chapter 2 if you are confused about importing modules\n", + "from math import pi\n", + "\n", + "def sin_inv_x(x):\n", + " if x == 0.0:\n", + " result = 0.0\n", + " else:\n", + " result = sin(1.0/x)\n", + " return result\n", + "\n", + "print(sin_inv_x(0))\n", + "print(sin_inv_x(pi))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This function has got documentation on it. The docstring is inside triple double quotes and it is the first string literal in the function." + ] + }, + { + "cell_type": "code", + "execution_count": 76, + "metadata": {}, + "outputs": [], + "source": [ + "def power(base, x):\n", + " \"\"\"Computes base^x. Both base and x should be integers,\n", + " floats, or another numeric type.\n", + " \"\"\"\n", + " return base**x\n", + "\n", + "#uncomment the next line to view the docstring for the power function\n", + "# ?power" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Keyword arguments" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Keyword arguments allow a programmer to assign a default value to a function that may be changed. Keywrod arguments provide three main advantages. They redyce the amount of information that must be explicitly passed to a function, they may be called in any order, and help define the kinds of values that may be passed to the function. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We've got a few examples of functions with keyword arguments in the following cells." + ] + }, + { + "cell_type": "code", + "execution_count": 78, + "metadata": {}, + "outputs": [], + "source": [ + "def line(x, a=1.0, b=0.0):\n", + " return a*x + b" + ] + }, + { + "cell_type": "code", + "execution_count": 79, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "42.0" + ] + }, + "execution_count": 79, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "line(42) # no keyword args, returns 1*42 + 0" + ] + }, + { + "cell_type": "code", + "execution_count": 80, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "84.0" + ] + }, + "execution_count": 80, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "line(42, 2) # a=2, returns 84" + ] + }, + { + "cell_type": "code", + "execution_count": 81, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "52.0" + ] + }, + "execution_count": 81, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "line(42, b=10) # b=10, returns 52" + ] + }, + { + "cell_type": "code", + "execution_count": 82, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "94" + ] + }, + "execution_count": 82, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "line(42, b=10, a=2) # returns 94 " + ] + }, + { + "cell_type": "code", + "execution_count": 88, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "94" + ] + }, + "execution_count": 88, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "line(42, a=2, b=10) # also returns 94 " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Mutable objects like lists do not make good keyword arguments. Because they are mutable, they retain their state from one call to the next, producing hard-to-find bugs." + ] + }, + { + "cell_type": "code", + "execution_count": 89, + "metadata": {}, + "outputs": [], + "source": [ + "# Do not do this!\n", + "def myappend(x, lyst=[]):\n", + " lyst.append(x)\n", + " return lyst" + ] + }, + { + "cell_type": "code", + "execution_count": 90, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[6]" + ] + }, + "execution_count": 90, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "myappend(6) # seems right" + ] + }, + { + "cell_type": "code", + "execution_count": 91, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[6, 42]" + ] + }, + "execution_count": 91, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "myappend(42) # hmmm..." + ] + }, + { + "cell_type": "code", + "execution_count": 92, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[1, 16, 12]" + ] + }, + "execution_count": 92, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "myappend(12, [1, 16])" + ] + }, + { + "cell_type": "code", + "execution_count": 94, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[6, 42, 65, 65]" + ] + }, + "execution_count": 94, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "myappend(65) # nope, not right!" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Here is a safer way of writing the preceding function:" + ] + }, + { + "cell_type": "code", + "execution_count": 95, + "metadata": {}, + "outputs": [], + "source": [ + "def myappend(x, lyst=None):\n", + " if lyst is None:\n", + " lyst = []\n", + " lyst.append(x)\n", + " return lyst" + ] + }, + { + "cell_type": "code", + "execution_count": 96, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[6]" + ] + }, + "execution_count": 96, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "myappend(6) " + ] + }, + { + "cell_type": "code", + "execution_count": 97, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[42]" + ] + }, + "execution_count": 97, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "myappend(42)" + ] + }, + { + "cell_type": "code", + "execution_count": 98, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[1, 16, 12]" + ] + }, + "execution_count": 98, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "myappend(12, [1, 16])" + ] + }, + { + "cell_type": "code", + "execution_count": 100, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[65]" + ] + }, + "execution_count": 100, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "myappend(65)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Variable number of arguments" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Some functions can take a variable number of arguments. One function that makes good use of this property is the the max() function, which returns the largest numberical argument supplied to it. If max() had to take a fixed number of arguments, we'd have to store all of its data into a byzantine data structure before use." + ] + }, + { + "cell_type": "code", + "execution_count": 101, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "6" + ] + }, + "execution_count": 101, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "max(6, 2)" + ] + }, + { + "cell_type": "code", + "execution_count": 102, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "42" + ] + }, + "execution_count": 102, + "metadata": {}, + "output_type": "execute_result" } ], - "metadata": {} + "source": [ + "max(6, 42)" + ] + }, + { + "cell_type": "code", + "execution_count": 103, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "16" + ] + }, + "execution_count": 103, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "max(1, 16, 12)" + ] + }, + { + "cell_type": "code", + "execution_count": 104, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "65" + ] + }, + "execution_count": 104, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "max(65, 42, 2, 8)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The following example teaches us how to write a function that takes a variable number of arguments. We put a start in front of an argument. Anything that is supplied as an argument is then packed into a tuple, which can be unpacked in the function." + ] + }, + { + "cell_type": "code", + "execution_count": 108, + "metadata": {}, + "outputs": [], + "source": [ + "def minimum(*args):\n", + " \"\"\"Takes any number of arguments!\"\"\"\n", + " m = args[0]\n", + " for x in args[1:]:\n", + " if x < m:\n", + " m = x\n", + " return m " + ] + }, + { + "cell_type": "code", + "execution_count": 109, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "6" + ] + }, + "execution_count": 109, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "minimum(6, 42)" + ] + }, + { + "cell_type": "code", + "execution_count": 110, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "2" + ] + }, + "execution_count": 110, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "data = [65, 42, 2, 8]\n", + "minimum(*data)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Writing our functions this way allows us to separate data preparation from data processing. This is very exciting!" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We may want to make a function that takes a variable number of keyword arguments. This is different from passing a variable number of positional arguments in two ways. The first is that we use double stars to indicate the keyword arguments, the second is that the keyword arguments are packed into a dictionary." + ] + }, + { + "cell_type": "code", + "execution_count": 111, + "metadata": {}, + "outputs": [], + "source": [ + "def blender(*args, **kwargs):\n", + " \"\"\"Will it?\"\"\"\n", + " print(args, kwargs)" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "('yes', 42) {}\n" + ] + } + ], + "source": [ + "blender(\"yes\", 42)" + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "() {'x': 42, 'z': 6}\n" + ] + } + ], + "source": [ + "blender(z=6, x=42)" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "('no', [1], 'yes') {'x': 42, 'z': 6}\n" + ] + } + ], + "source": [ + "blender(\"no\", [1], \"yes\", z=6, x=42)" + ] + }, + { + "cell_type": "code", + "execution_count": 114, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "('yes', 'no') {'kid': 'covalent', 'mom': 'ionic'}\n" + ] + } + ], + "source": [ + "t = (\"no\",)\n", + "d = {\"mom\": \"ionic\"}\n", + "blender(\"yes\", kid=\"covalent\", *t, **d)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Multiple return values" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Python also lets us return multiple values from one function. All of the returned values will be stored into a tuple. Please note that we write\n", + "\n", + " return val1, val2 ... \n", + " \n", + "On the same line because python will stop executing a function after the first return." + ] + }, + { + "cell_type": "code", + "execution_count": 115, + "metadata": {}, + "outputs": [], + "source": [ + "def momentum_energy(m, v):\n", + " p = m * v\n", + " e = 0.5 * m * v**2\n", + " return p, e" + ] + }, + { + "cell_type": "code", + "execution_count": 116, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "(2730.0, 88725.0)\n" + ] + } + ], + "source": [ + "# returns a tuple\n", + "p_e = momentum_energy(42.0, 65.0)\n", + "print(p_e)" + ] + }, + { + "cell_type": "code", + "execution_count": 119, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2730.0\n" + ] + } + ], + "source": [ + "# unpacks the tuple\n", + "mom, eng = momentum_energy(42.0, 65.0)\n", + "print(mom)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Scope" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "All variables have \"scope\" relative to any given function. Variables that are defined inside a function have scope that is \"local\" to that function. Local variables have lifetimes that end when their function finishes executing. Those variables that are defined outside of any function have \"global\" or \"module\" scope. \n", + "\n", + "A variable is said to be \"out of scope\" when it cannot be accessed because it exists in another function." + ] + }, + { + "cell_type": "code", + "execution_count": 122, + "metadata": {}, + "outputs": [], + "source": [ + "# global scope\n", + "a = 6\n", + "b = 42\n", + "\n", + "def func(x, y):\n", + " # local scope\n", + " z = 16\n", + " return a*x + b*y + z\n", + "\n", + "# global scope\n", + "c = func(1, 5)" + ] + }, + { + "cell_type": "code", + "execution_count": 123, + "metadata": {}, + "outputs": [], + "source": [ + "# global scope\n", + "a = 6\n", + "b = 42\n", + "\n", + "def outer(m, n):\n", + " # outer's scope\n", + " p = 10 \n", + "\n", + " def inner(x, y):\n", + " # inner's scope\n", + " return a*p*x + b*n*y\n", + "\n", + " # outer's scope\n", + " return inner(m+1, n+1)\n", + "\n", + "# global scope\n", + "c = outer(1, 5)" + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "6\n", + "42\n", + "6\n" + ] + } + ], + "source": [ + "a = 6\n", + "\n", + "def a_global():\n", + " print(a)\n", + "\n", + "def a_local():\n", + " a = 42\n", + " print(a)\n", + "\n", + "a_global()\n", + "a_local()\n", + "print(a)" + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "metadata": {}, + "outputs": [ + { + "ename": "UnboundLocalError", + "evalue": "local variable 'a' referenced before assignment", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mUnboundLocalError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 8\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"small \"\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0ma\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 9\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 10\u001b[0;31m \u001b[0mfunc\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m\u001b[0m in \u001b[0;36mfunc\u001b[0;34m()\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mfunc\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 4\u001b[0m \u001b[0;31m# you cannot use the global 'a' because...\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 5\u001b[0;31m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Big \"\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0ma\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 6\u001b[0m \u001b[0;31m# a local 'a' is eventually defined!\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 7\u001b[0m \u001b[0ma\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m\"a\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mUnboundLocalError\u001b[0m: local variable 'a' referenced before assignment" + ] + } + ], + "source": [ + "a = \"A\"\n", + "\n", + "def func():\n", + " # you cannot use the global 'a' because...\n", + " print(\"Big \" + a)\n", + " # a local 'a' is eventually defined!\n", + " a = \"a\"\n", + " print(\"small \" + a)\n", + "\n", + "func()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "a = \"A\"\n", + "\n", + "def func():\n", + " global a\n", + " print(\"Big \" + a)\n", + " a = \"a\"\n", + " print(\"small \" + a)\n", + "\n", + "func()\n", + "print(\"global \" + a)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# DO NOT RUN THIS\n", + "#def func():\n", + "# func()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def fib(n):\n", + " if n == 0 or n == 1:\n", + " return n\n", + " else:\n", + " return fib(n - 1) + fib(n - 2)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import sys\n", + "sys.getrecursionlimit() # return the current limit\n", + "sys.setrecursionlimit(8128) # change the limit to 8128" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# a simple lambda\n", + "lambda x: x**2" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# a lambda that is called after it is defined\n", + "(lambda x, y=10: 2*x + y)(42)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# just because it is anonymous doesn't mean we can't give it a name!\n", + "f = lambda: [x**2 for x in range(10)]\n", + "f()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# a lambda as a dict value\n", + "d = {'null': lambda *args, **kwargs: None}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# a lambda as a keyword argument f in another function\n", + "def func(vals, f=lambda x: sum(x)/len(x)):\n", + " f(vals)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# a lambda as a keyword argument in a function call\n", + "func([6, 28, 496, 8128], lambda data: sum([x**2 for x in data]))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "nums = [8128, 6, 496, 28]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "sorted(nums)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "sorted(nums, key=lambda x: x%13)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def countdown():\n", + " yield 3\n", + " yield 2\n", + " yield 1\n", + " yield 'Blast off!'" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# generator\n", + "g = countdown()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "next(g)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "x = next(g)\n", + "print(x)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "y, z = next(g), next(g)\n", + "print(z)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "next(g)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "for t in countdown():\n", + " if isinstance(t, int):\n", + " message = \"T-\" + str(t)\n", + " else:\n", + " message = t\n", + " print(message)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def square_plus_one(n):\n", + " for x in range(n):\n", + " x2 = x * x\n", + " yield x2 + 1" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "for sp1 in square_plus_one(3):\n", + " print(sp1)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# define a subgenerator\n", + "def yield_all(x):\n", + " for i in x:\n", + " yield i\n", + "\n", + "# palindrome using yield froms\n", + "def palindromize(x):\n", + " yield from yield_all(x)\n", + " yield from yield_all(x[::-1])\n", + "\n", + "# the above is equivalent to this full expansion:\n", + "def palindromize_explicit(x):\n", + " for i in x:\n", + " yield i\n", + " for i in x[::-1]:\n", + " yield i" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def null(f):\n", + " \"\"\"Always return None.\"\"\"\n", + " return\n", + "\n", + "def identity(f):\n", + " \"\"\"Return the function.\"\"\"\n", + " return f\n", + "\n", + "def self_referential(f):\n", + " \"\"\"Return the decorator.\"\"\"\n", + " return self_referential" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "@null\n", + "def nargs(*args, **kwargs):\n", + " return len(args) + len(kwargs)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def nargs(*args, **kwargs):\n", + " return len(args) + len(kwargs)\n", + "nargs = null(nargs)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def plus1(f):\n", + " def wrapper(*args, **kwargs):\n", + " return f(*args, **kwargs) + 1\n", + " return wrapper" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "@plus1\n", + "def power(base, x):\n", + " return base**x\n", + "\n", + "power(4, 2)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "@plus1\n", + "@identity\n", + "@plus1\n", + "@plus1\n", + "def root(x):\n", + " return x**0.5\n", + "\n", + "root(4)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def plus_n(n):\n", + " def dec(f):\n", + " def wrapper(*args, **kwargs):\n", + " return f(*args, **kwargs) + n\n", + " return wrapper\n", + " return dec" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "@plus_n(6)\n", + "def root(x):\n", + " return x**0.5\n", + "\n", + "root(4)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "max = plus1(max)" + ] } - ] -} \ No newline at end of file + ], + "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.6" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/ch06-classes-objects.ipynb b/ch06-classes-objects.ipynb index e81c04b..e741b3a 100644 --- a/ch06-classes-objects.ipynb +++ b/ch06-classes-objects.ipynb @@ -1,1153 +1,2269 @@ { - "metadata": { - "name": "", - "signature": "sha256:f836ba88dad05ca9c5ff6f99f0bf19326ed9dc3a96982a4c1b2c9f489ea8e900" - }, - "nbformat": 3, - "nbformat_minor": 0, - "worksheets": [ + "cells": [ { - "cells": [ - { - "cell_type": "code", - "collapsed": false, - "input": [ - "a = 1\n", - "help(a)" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "Help on int object:\n", - "\n", - "class int(object)\n", - " | int(x=0) -> integer\n", - " | int(x, base=10) -> integer\n", - " | \n", - " | Convert a number or string to an integer, or return 0 if no arguments\n", - " | are given. If x is a number, return x.__int__(). For floating point\n", - " | numbers, this truncates towards zero.\n", - " | \n", - " | If x is not a number or if base is given, then x must be a string,\n", - " | bytes, or bytearray instance representing an integer literal in the\n", - " | given base. The literal can be preceded by '+' or '-' and be surrounded\n", - " | by whitespace. The base defaults to 10. Valid bases are 0 and 2-36.\n", - " | Base 0 means to interpret the base from the string as an integer literal.\n", - " | >>> int('0b100', base=0)\n", - " | 4\n", - " | \n", - " | Methods defined here:\n", - " | \n", - " | __abs__(self, /)\n", - " | abs(self)\n", - " | \n", - " | __add__(self, value, /)\n", - " | Return self+value.\n", - " | \n", - " | __and__(self, value, /)\n", - " | Return self&value.\n", - " | \n", - " | __bool__(self, /)\n", - " | self != 0\n", - " | \n", - " | __ceil__(...)\n", - " | Ceiling of an Integral returns itself.\n", - " | \n", - " | __divmod__(self, value, /)\n", - " | Return divmod(self, value).\n", - " | \n", - " | __eq__(self, value, /)\n", - " | Return self==value.\n", - " | \n", - " | __float__(self, /)\n", - " | float(self)\n", - " | \n", - " | __floor__(...)\n", - " | Flooring an Integral returns itself.\n", - " | \n", - " | __floordiv__(self, value, /)\n", - " | Return self//value.\n", - " | \n", - " | __format__(...)\n", - " | \n", - " | __ge__(self, value, /)\n", - " | Return self>=value.\n", - " | \n", - " | __getattribute__(self, name, /)\n", - " | Return getattr(self, name).\n", - " | \n", - " | __getnewargs__(...)\n", - " | \n", - " | __gt__(self, value, /)\n", - " | Return self>value.\n", - " | \n", - " | __hash__(self, /)\n", - " | Return hash(self).\n", - " | \n", - " | __index__(self, /)\n", - " | Return self converted to an integer, if self is suitable for use as an index into a list.\n", - " | \n", - " | __int__(self, /)\n", - " | int(self)\n", - " | \n", - " | __invert__(self, /)\n", - " | ~self\n", - " | \n", - " | __le__(self, value, /)\n", - " | Return self<=value.\n", - " | \n", - " | __lshift__(self, value, /)\n", - " | Return self<>self.\n", - " | \n", - " | __rshift__(self, value, /)\n", - " | Return self>>value.\n", - " | \n", - " | __rsub__(self, value, /)\n", - " | Return value-self.\n", - " | \n", - " | __rtruediv__(self, value, /)\n", - " | Return value/self.\n", - " | \n", - " | __rxor__(self, value, /)\n", - " | Return value^self.\n", - " | \n", - " | __sizeof__(...)\n", - " | Returns size in memory, in bytes\n", - " | \n", - " | __str__(self, /)\n", - " | Return str(self).\n", - " | \n", - " | __sub__(self, value, /)\n", - " | Return self-value.\n", - " | \n", - " | __truediv__(self, value, /)\n", - " | Return self/value.\n", - " | \n", - " | __trunc__(...)\n", - " | Truncating an Integral returns itself.\n", - " | \n", - " | __xor__(self, value, /)\n", - " | Return self^value.\n", - " | \n", - " | bit_length(...)\n", - " | int.bit_length() -> int\n", - " | \n", - " | Number of bits necessary to represent self in binary.\n", - " | >>> bin(37)\n", - " | '0b100101'\n", - " | >>> (37).bit_length()\n", - " | 6\n", - " | \n", - " | conjugate(...)\n", - " | Returns self, the complex conjugate of any int.\n", - " | \n", - " | from_bytes(...) from builtins.type\n", - " | int.from_bytes(bytes, byteorder, *, signed=False) -> int\n", - " | \n", - " | Return the integer represented by the given array of bytes.\n", - " | \n", - " | The bytes argument must either support the buffer protocol or be an\n", - " | iterable object producing bytes. Bytes and bytearray are examples of\n", - " | built-in objects that support the buffer protocol.\n", - " | \n", - " | The byteorder argument determines the byte order used to represent the\n", - " | integer. If byteorder is 'big', the most significant byte is at the\n", - " | beginning of the byte array. If byteorder is 'little', the most\n", - " | significant byte is at the end of the byte array. To request the native\n", - " | byte order of the host system, use `sys.byteorder' as the byte order value.\n", - " | \n", - " | The signed keyword-only argument indicates whether two's complement is\n", - " | used to represent the integer.\n", - " | \n", - " | to_bytes(...)\n", - " | int.to_bytes(length, byteorder, *, signed=False) -> bytes\n", - " | \n", - " | Return an array of bytes representing an integer.\n", - " | \n", - " | The integer is represented using length bytes. An OverflowError is\n", - " | raised if the integer is not representable with the given number of\n", - " | bytes.\n", - " | \n", - " | The byteorder argument determines the byte order used to represent the\n", - " | integer. If byteorder is 'big', the most significant byte is at the\n", - " | beginning of the byte array. If byteorder is 'little', the most\n", - " | significant byte is at the end of the byte array. To request the native\n", - " | byte order of the host system, use `sys.byteorder' as the byte order value.\n", - " | \n", - " | The signed keyword-only argument determines whether two's complement is\n", - " | used to represent the integer. If signed is False and a negative integer\n", - " | is given, an OverflowError is raised.\n", - " | \n", - " | ----------------------------------------------------------------------\n", - " | Data descriptors defined here:\n", - " | \n", - " | denominator\n", - " | the denominator of a rational number in lowest terms\n", - " | \n", - " | imag\n", - " | the imaginary part of a complex number\n", - " | \n", - " | numerator\n", - " | the numerator of a rational number in lowest terms\n", - " | \n", - " | real\n", - " | the real part of a complex number\n", - "\n" - ] - } - ], - "prompt_number": 1 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "a = 1\n", - "dir(a)" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 2, - "text": [ - "['__abs__',\n", - " '__add__',\n", - " '__and__',\n", - " '__bool__',\n", - " '__ceil__',\n", - " '__class__',\n", - " '__delattr__',\n", - " '__dir__',\n", - " '__divmod__',\n", - " '__doc__',\n", - " '__eq__',\n", - " '__float__',\n", - " '__floor__',\n", - " '__floordiv__',\n", - " '__format__',\n", - " '__ge__',\n", - " '__getattribute__',\n", - " '__getnewargs__',\n", - " '__gt__',\n", - " '__hash__',\n", - " '__index__',\n", - " '__init__',\n", - " '__int__',\n", - " '__invert__',\n", - " '__le__',\n", - " '__lshift__',\n", - " '__lt__',\n", - " '__mod__',\n", - " '__mul__',\n", - " '__ne__',\n", - " '__neg__',\n", - " '__new__',\n", - " '__or__',\n", - " '__pos__',\n", - " '__pow__',\n", - " '__radd__',\n", - " '__rand__',\n", - " '__rdivmod__',\n", - " '__reduce__',\n", - " '__reduce_ex__',\n", - " '__repr__',\n", - " '__rfloordiv__',\n", - " '__rlshift__',\n", - " '__rmod__',\n", - " '__rmul__',\n", - " '__ror__',\n", - " '__round__',\n", - " '__rpow__',\n", - " '__rrshift__',\n", - " '__rshift__',\n", - " '__rsub__',\n", - " '__rtruediv__',\n", - " '__rxor__',\n", - " '__setattr__',\n", - " '__sizeof__',\n", - " '__str__',\n", - " '__sub__',\n", - " '__subclasshook__',\n", - " '__truediv__',\n", - " '__trunc__',\n", - " '__xor__',\n", - " 'bit_length',\n", - " 'conjugate',\n", - " 'denominator',\n", - " 'from_bytes',\n", - " 'imag',\n", - " 'numerator',\n", - " 'real',\n", - " 'to_bytes']" - ] - } - ], - "prompt_number": 2 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "a = 1\n", - "a.__abs__()" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 3, - "text": [ - "1" - ] - } - ], - "prompt_number": 3 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "b = -2\n", - "b.__abs__()" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 4, - "text": [ - "2" - ] - } - ], - "prompt_number": 4 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "a = 1\n", - "abs(a)" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 5, - "text": [ - "1" - ] - } - ], - "prompt_number": 5 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "b = -2\n", - "abs(b)" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 6, - "text": [ - "2" - ] - } - ], - "prompt_number": 6 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "import math\n", - "dir(math.sin)" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 7, - "text": [ - "['__call__',\n", - " '__class__',\n", - " '__delattr__',\n", - " '__dir__',\n", - " '__doc__',\n", - " '__eq__',\n", - " '__format__',\n", - " '__ge__',\n", - " '__getattribute__',\n", - " '__gt__',\n", - " '__hash__',\n", - " '__init__',\n", - " '__le__',\n", - " '__lt__',\n", - " '__module__',\n", - " '__name__',\n", - " '__ne__',\n", - " '__new__',\n", - " '__qualname__',\n", - " '__reduce__',\n", - " '__reduce_ex__',\n", - " '__repr__',\n", - " '__self__',\n", - " '__setattr__',\n", - " '__sizeof__',\n", - " '__str__',\n", - " '__subclasshook__',\n", - " '__text_signature__']" - ] - } - ], - "prompt_number": 7 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "import math \n", - "math.sin.__doc__" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 8, - "text": [ - "'sin(x)\\n\\nReturn the sine of x (measured in radians).'" - ] - } - ], - "prompt_number": 8 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "class Particle(object):\n", - " \"\"\"A particle is a constituent unit of the universe.\"\"\"\n", - " # class body definition here" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 9 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "# particle.py\n", - "class Particle(object):\n", - " \"\"\"A particle is a constituent unit of the universe.\"\"\"\n", - " roar = \"I am a particle!\" " - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 10 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "import os\n", - "import sys\n", - "sys.path.insert(0, os.path.abspath('obj'))" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 11 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "# import the particle module\n", - "import particle as p\n", - "print(p.Particle.roar)" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "I am a particle!\n" - ] - } - ], - "prompt_number": 12 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "# import the particle module\n", - "import particle as p\n", - "higgs = p.Particle()\n", - "print(higgs.roar)" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "I am a particle!\n" - ] - } - ], - "prompt_number": 13 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "# import the Particle class from the particle module\n", - "from particle import Particle\n", - "\n", - "# create an empty list to hold observed particle data\n", - "obs = []\n", - "\n", - "# append the first particle\n", - "obs.append(Particle())\n", - "\n", - "# assign its position\n", - "obs[0].r = {'x': 100.0, 'y': 38.0, 'z': -42.0}\n", - "\n", - "# append the second particle\n", - "obs.append(Particle())\n", - "\n", - "# assign the position of the second particle\n", - "obs[1].r = {'x': 0.01, 'y': 99.0, 'z': 32.0}\n", - "\n", - "# print the positions of each particle\n", - "print(obs[0].r)\n", - "print(obs[1].r)" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "{'x': 100.0, 'z': -42.0, 'y': 38.0}\n", - "{'x': 0.01, 'z': 32.0, 'y': 99.0}\n" - ] - } - ], - "prompt_number": 14 - }, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Classes and Objects" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Object Orienation is a powerful tool that allows scientists to write larger, more complex simulations. Object orientation organizes data, methods, and functions into classes. Pages 117 and 118 provide a great introduction to this topic." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Objects\n", + "\n", + "Everything in python is an object. We will use the help() function to view the docstrings of a simple object. The following exercise tells us that the integer 1 is an object belonging to the class int." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "collapsed": false, - "input": [ - "# particle.py\n", - "class Particle(object):\n", - " \"\"\"A particle is a constituent unit of the universe.\n", - " \n", - " Attributes\n", - " ----------\n", - " c : charge in units of [e]\n", - " m : mass in units of [kg]\n", - " r : position in units of [meters]\n", - " \"\"\"\n", - "\n", - " roar = \"I am a particle!\"\n", + "name": "stdout", + "output_type": "stream", + "text": [ + "Help on int object:\n", "\n", - " def __init__(self):\n", - " \"\"\"Initializes the particle with default values for \n", - " charge c, mass m, and position r.\n", - " \"\"\"\n", - " self.c = 0\n", - " self.m = 0\n", - " self.r = {'x': 0, 'y': 0, 'z': 0}\n" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 15 - }, + "class int(object)\n", + " | int(x=0) -> integer\n", + " | int(x, base=10) -> integer\n", + " | \n", + " | Convert a number or string to an integer, or return 0 if no arguments\n", + " | are given. If x is a number, return x.__int__(). For floating point\n", + " | numbers, this truncates towards zero.\n", + " | \n", + " | If x is not a number or if base is given, then x must be a string,\n", + " | bytes, or bytearray instance representing an integer literal in the\n", + " | given base. The literal can be preceded by '+' or '-' and be surrounded\n", + " | by whitespace. The base defaults to 10. Valid bases are 0 and 2-36.\n", + " | Base 0 means to interpret the base from the string as an integer literal.\n", + " | >>> int('0b100', base=0)\n", + " | 4\n", + " | \n", + " | Methods defined here:\n", + " | \n", + " | __abs__(self, /)\n", + " | abs(self)\n", + " | \n", + " | __add__(self, value, /)\n", + " | Return self+value.\n", + " | \n", + " | __and__(self, value, /)\n", + " | Return self&value.\n", + " | \n", + " | __bool__(self, /)\n", + " | self != 0\n", + " | \n", + " | __ceil__(...)\n", + " | Ceiling of an Integral returns itself.\n", + " | \n", + " | __divmod__(self, value, /)\n", + " | Return divmod(self, value).\n", + " | \n", + " | __eq__(self, value, /)\n", + " | Return self==value.\n", + " | \n", + " | __float__(self, /)\n", + " | float(self)\n", + " | \n", + " | __floor__(...)\n", + " | Flooring an Integral returns itself.\n", + " | \n", + " | __floordiv__(self, value, /)\n", + " | Return self//value.\n", + " | \n", + " | __format__(...)\n", + " | default object formatter\n", + " | \n", + " | __ge__(self, value, /)\n", + " | Return self>=value.\n", + " | \n", + " | __getattribute__(self, name, /)\n", + " | Return getattr(self, name).\n", + " | \n", + " | __getnewargs__(...)\n", + " | \n", + " | __gt__(self, value, /)\n", + " | Return self>value.\n", + " | \n", + " | __hash__(self, /)\n", + " | Return hash(self).\n", + " | \n", + " | __index__(self, /)\n", + " | Return self converted to an integer, if self is suitable for use as an index into a list.\n", + " | \n", + " | __int__(self, /)\n", + " | int(self)\n", + " | \n", + " | __invert__(self, /)\n", + " | ~self\n", + " | \n", + " | __le__(self, value, /)\n", + " | Return self<=value.\n", + " | \n", + " | __lshift__(self, value, /)\n", + " | Return self<>self.\n", + " | \n", + " | __rshift__(self, value, /)\n", + " | Return self>>value.\n", + " | \n", + " | __rsub__(self, value, /)\n", + " | Return value-self.\n", + " | \n", + " | __rtruediv__(self, value, /)\n", + " | Return value/self.\n", + " | \n", + " | __rxor__(self, value, /)\n", + " | Return value^self.\n", + " | \n", + " | __sizeof__(...)\n", + " | Returns size in memory, in bytes\n", + " | \n", + " | __str__(self, /)\n", + " | Return str(self).\n", + " | \n", + " | __sub__(self, value, /)\n", + " | Return self-value.\n", + " | \n", + " | __truediv__(self, value, /)\n", + " | Return self/value.\n", + " | \n", + " | __trunc__(...)\n", + " | Truncating an Integral returns itself.\n", + " | \n", + " | __xor__(self, value, /)\n", + " | Return self^value.\n", + " | \n", + " | bit_length(...)\n", + " | int.bit_length() -> int\n", + " | \n", + " | Number of bits necessary to represent self in binary.\n", + " | >>> bin(37)\n", + " | '0b100101'\n", + " | >>> (37).bit_length()\n", + " | 6\n", + " | \n", + " | conjugate(...)\n", + " | Returns self, the complex conjugate of any int.\n", + " | \n", + " | from_bytes(...) from builtins.type\n", + " | int.from_bytes(bytes, byteorder, *, signed=False) -> int\n", + " | \n", + " | Return the integer represented by the given array of bytes.\n", + " | \n", + " | The bytes argument must be a bytes-like object (e.g. bytes or bytearray).\n", + " | \n", + " | The byteorder argument determines the byte order used to represent the\n", + " | integer. If byteorder is 'big', the most significant byte is at the\n", + " | beginning of the byte array. If byteorder is 'little', the most\n", + " | significant byte is at the end of the byte array. To request the native\n", + " | byte order of the host system, use `sys.byteorder' as the byte order value.\n", + " | \n", + " | The signed keyword-only argument indicates whether two's complement is\n", + " | used to represent the integer.\n", + " | \n", + " | to_bytes(...)\n", + " | int.to_bytes(length, byteorder, *, signed=False) -> bytes\n", + " | \n", + " | Return an array of bytes representing an integer.\n", + " | \n", + " | The integer is represented using length bytes. An OverflowError is\n", + " | raised if the integer is not representable with the given number of\n", + " | bytes.\n", + " | \n", + " | The byteorder argument determines the byte order used to represent the\n", + " | integer. If byteorder is 'big', the most significant byte is at the\n", + " | beginning of the byte array. If byteorder is 'little', the most\n", + " | significant byte is at the end of the byte array. To request the native\n", + " | byte order of the host system, use `sys.byteorder' as the byte order value.\n", + " | \n", + " | The signed keyword-only argument determines whether two's complement is\n", + " | used to represent the integer. If signed is False and a negative integer\n", + " | is given, an OverflowError is raised.\n", + " | \n", + " | ----------------------------------------------------------------------\n", + " | Data descriptors defined here:\n", + " | \n", + " | denominator\n", + " | the denominator of a rational number in lowest terms\n", + " | \n", + " | imag\n", + " | the imaginary part of a complex number\n", + " | \n", + " | numerator\n", + " | the numerator of a rational number in lowest terms\n", + " | \n", + " | real\n", + " | the real part of a complex number\n", + "\n" + ] + } + ], + "source": [ + "a = 1\n", + "help(a)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The help() function has told us that the integer is an object. This object must have be associated with rules and behaviors. The dir() function will tell us about some of those behaviors. The dir() function lists all of the attributes and methods associated with the argument. " + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "collapsed": false, - "input": [ - "# particle.py\n", - "class Particle(object):\n", - " \"\"\"A particle is a constituent unit of the universe.\n", - " \n", - " Attributes\n", - " ----------\n", - " c : charge in units of [e]\n", - " m : mass in units of [kg]\n", - " r : position in units of [meters]\n", - " \"\"\"\n", - "\n", - " roar = \"I am a particle!\"\n", - "\n", - " def __init__(self, charge, mass, position):\n", - " \"\"\"Initializes the particle with supplied values for \n", - " charge c, mass m, and position r.\n", - " \"\"\"\n", - " self.c = charge\n", - " self.m = mass\n", - " self.r = position\n" - ], - "language": "python", + "data": { + "text/plain": [ + "['__abs__',\n", + " '__add__',\n", + " '__and__',\n", + " '__bool__',\n", + " '__ceil__',\n", + " '__class__',\n", + " '__delattr__',\n", + " '__dir__',\n", + " '__divmod__',\n", + " '__doc__',\n", + " '__eq__',\n", + " '__float__',\n", + " '__floor__',\n", + " '__floordiv__',\n", + " '__format__',\n", + " '__ge__',\n", + " '__getattribute__',\n", + " '__getnewargs__',\n", + " '__gt__',\n", + " '__hash__',\n", + " '__index__',\n", + " '__init__',\n", + " '__int__',\n", + " '__invert__',\n", + " '__le__',\n", + " '__lshift__',\n", + " '__lt__',\n", + " '__mod__',\n", + " '__mul__',\n", + " '__ne__',\n", + " '__neg__',\n", + " '__new__',\n", + " '__or__',\n", + " '__pos__',\n", + " '__pow__',\n", + " '__radd__',\n", + " '__rand__',\n", + " '__rdivmod__',\n", + " '__reduce__',\n", + " '__reduce_ex__',\n", + " '__repr__',\n", + " '__rfloordiv__',\n", + " '__rlshift__',\n", + " '__rmod__',\n", + " '__rmul__',\n", + " '__ror__',\n", + " '__round__',\n", + " '__rpow__',\n", + " '__rrshift__',\n", + " '__rshift__',\n", + " '__rsub__',\n", + " '__rtruediv__',\n", + " '__rxor__',\n", + " '__setattr__',\n", + " '__sizeof__',\n", + " '__str__',\n", + " '__sub__',\n", + " '__subclasshook__',\n", + " '__truediv__',\n", + " '__trunc__',\n", + " '__xor__',\n", + " 'bit_length',\n", + " 'conjugate',\n", + " 'denominator',\n", + " 'from_bytes',\n", + " 'imag',\n", + " 'numerator',\n", + " 'real',\n", + " 'to_bytes']" + ] + }, + "execution_count": 4, "metadata": {}, - "outputs": [], - "prompt_number": 16 - }, + "output_type": "execute_result" + } + ], + "source": [ + "a = 1\n", + "dir(a)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Dir() has told us that objects in the int class have absolute values(\\__abs__), and that they may be added together (\\__add__). These objects also have real (real) and imaginary (imag) components." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "collapsed": false, - "input": [ - "# particle.py\n", - "class Particle(object):\n", - " \"\"\"A particle is a constituent unit of the universe.\n", - " \n", - " Attributes\n", - " ----------\n", - " c : charge in units of [e]\n", - " m : mass in units of [kg]\n", - " r : position in units of [meters]\n", - " \"\"\"\n", - "\n", - " roar = \"I am a particle!\"\n", - "\n", - " def __init__(self, charge, mass, position): \n", - " \"\"\"Initializes the particle with supplied values for \n", - " charge c, mass m, and position r.\n", - " \"\"\"\n", - " self.c = charge\n", - " self.m = mass\n", - " self.r = position\n", - "\n", - " def hear_me(self):\n", - " myroar = self.roar + (\n", - " \" My charge is: \" + str(self.c) + \n", - " \" My mass is: \" + str(self.m) +\n", - " \" My x position is: \" + str(self.r['x']) +\n", - " \" My y position is: \" + str(self.r['y']) +\n", - " \" My z position is: \" + str(self.r['z']))\n", - " print(myroar)" - ], - "language": "python", + "data": { + "text/plain": [ + "1" + ] + }, + "execution_count": 5, "metadata": {}, - "outputs": [], - "prompt_number": 17 - }, + "output_type": "execute_result" + } + ], + "source": [ + "a = 1\n", + "a.__abs__()" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "collapsed": false, - "input": [ - "from scipy import constants\n", - "\n", - "import particle as p\n", - "\n", - "m_p = constants.m_p\n", - "r_p = {'x': 1, 'y': 1, 'z': 53}\n", - "a_p = p.Particle(1, m_p, r_p)\n", - "a_p.hear_me()" - ], - "language": "python", + "data": { + "text/plain": [ + "2" + ] + }, + "execution_count": 8, "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "I am a particle!\n", - " My mass is: 1.672621777e-27\n", - " My charge is: 1\n", - " My x position is: 1\n", - " My y position is: 1\n", - " My z position is: 53\n" - ] - } - ], - "prompt_number": 18 - }, + "output_type": "execute_result" + } + ], + "source": [ + "b = -2\n", + "b.__abs__()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In the preceding cells, we have directly called the \\__abs__ method on two objects. However, it is almost never a good idea to directly call these double underscore (aka \"dunder\") methods. It is much safer to get the absolute value by just using the abs() function, as follows:" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "collapsed": false, - "input": [ - "def flip(self):\n", - " if self.flavor == \"up\":\n", - " self.flavor = \"down\"\n", - " elif self.flavor == \"down\":\n", - " self.flavor = \"up\"\n", - " elif self.flavor == \"top\":\n", - " self.flavor = \"bottom\"\n", - " elif self.flavor == \"bottom\":\n", - " self.flavor = \"top\"\n", - " elif self.flavor == \"strange\":\n", - " self.flavor = \"charm\"\n", - " elif self.flavor == \"charm\":\n", - " self.flavor = \"strange\"\n", - " else :\n", - " raise AttributeError(\"The quark cannot be flipped, because the \"\n", - " \"flavor is not valid.\")" - ], - "language": "python", + "data": { + "text/plain": [ + "1" + ] + }, + "execution_count": 7, "metadata": {}, - "outputs": [], - "prompt_number": 19 - }, + "output_type": "execute_result" + } + ], + "source": [ + "a = 1\n", + "abs(a)" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "collapsed": false, - "input": [ - "# import the class\n", - "from quark import Quark\n", - "\n", - "# create a Quark object\n", - "t = Quark()\n", - "\n", - "# set the flavor\n", - "t.flavor = \"top\"\n", - "\n", - "# flip the flavor\n", - "t.flip()\n", - "\n", - "# print the flavor\n", - "print(t.flavor)" - ], - "language": "python", + "data": { + "text/plain": [ + "2" + ] + }, + "execution_count": 9, "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "bottom\n" - ] - } - ], - "prompt_number": 20 - }, + "output_type": "execute_result" + } + ], + "source": [ + "b = -2\n", + "abs(b)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The help() and dir() functions are applied to some of the data types from chapter 2 in the following cells. You should try examining every data type you can think of." + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "collapsed": false, - "input": [ - "from scipy import constants\n", - "\n", - "class Particle(object):\n", - " \"\"\"A particle is a constituent unit of the universe.\"\"\"\n", + "name": "stdout", + "output_type": "stream", + "text": [ + "Help on class str in module builtins:\n", "\n", - " # ... other parts of the class definition ...\n", - "\n", - " def delta_x_min(self, delta_p_x):\n", - " hbar = constants.hbar\n", - " delx_min = hbar / (2.0 * delta_p_x)\n", - " return delx_min" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 21 + "class str(object)\n", + " | str(object='') -> str\n", + " | str(bytes_or_buffer[, encoding[, errors]]) -> str\n", + " | \n", + " | Create a new string object from the given object. If encoding or\n", + " | errors is specified, then the object must expose a data buffer\n", + " | that will be decoded using the given encoding and error handler.\n", + " | Otherwise, returns the result of object.__str__() (if defined)\n", + " | or repr(object).\n", + " | encoding defaults to sys.getdefaultencoding().\n", + " | errors defaults to 'strict'.\n", + " | \n", + " | Methods defined here:\n", + " | \n", + " | __add__(self, value, /)\n", + " | Return self+value.\n", + " | \n", + " | __contains__(self, key, /)\n", + " | Return key in self.\n", + " | \n", + " | __eq__(self, value, /)\n", + " | Return self==value.\n", + " | \n", + " | __format__(...)\n", + " | S.__format__(format_spec) -> str\n", + " | \n", + " | Return a formatted version of S as described by format_spec.\n", + " | \n", + " | __ge__(self, value, /)\n", + " | Return self>=value.\n", + " | \n", + " | __getattribute__(self, name, /)\n", + " | Return getattr(self, name).\n", + " | \n", + " | __getitem__(self, key, /)\n", + " | Return self[key].\n", + " | \n", + " | __getnewargs__(...)\n", + " | \n", + " | __gt__(self, value, /)\n", + " | Return self>value.\n", + " | \n", + " | __hash__(self, /)\n", + " | Return hash(self).\n", + " | \n", + " | __iter__(self, /)\n", + " | Implement iter(self).\n", + " | \n", + " | __le__(self, value, /)\n", + " | Return self<=value.\n", + " | \n", + " | __len__(self, /)\n", + " | Return len(self).\n", + " | \n", + " | __lt__(self, value, /)\n", + " | Return self size of S in memory, in bytes\n", + " | \n", + " | __str__(self, /)\n", + " | Return str(self).\n", + " | \n", + " | capitalize(...)\n", + " | S.capitalize() -> str\n", + " | \n", + " | Return a capitalized version of S, i.e. make the first character\n", + " | have upper case and the rest lower case.\n", + " | \n", + " | casefold(...)\n", + " | S.casefold() -> str\n", + " | \n", + " | Return a version of S suitable for caseless comparisons.\n", + " | \n", + " | center(...)\n", + " | S.center(width[, fillchar]) -> str\n", + " | \n", + " | Return S centered in a string of length width. Padding is\n", + " | done using the specified fill character (default is a space)\n", + " | \n", + " | count(...)\n", + " | S.count(sub[, start[, end]]) -> int\n", + " | \n", + " | Return the number of non-overlapping occurrences of substring sub in\n", + " | string S[start:end]. Optional arguments start and end are\n", + " | interpreted as in slice notation.\n", + " | \n", + " | encode(...)\n", + " | S.encode(encoding='utf-8', errors='strict') -> bytes\n", + " | \n", + " | Encode S using the codec registered for encoding. Default encoding\n", + " | is 'utf-8'. errors may be given to set a different error\n", + " | handling scheme. Default is 'strict' meaning that encoding errors raise\n", + " | a UnicodeEncodeError. Other possible values are 'ignore', 'replace' and\n", + " | 'xmlcharrefreplace' as well as any other name registered with\n", + " | codecs.register_error that can handle UnicodeEncodeErrors.\n", + " | \n", + " | endswith(...)\n", + " | S.endswith(suffix[, start[, end]]) -> bool\n", + " | \n", + " | Return True if S ends with the specified suffix, False otherwise.\n", + " | With optional start, test S beginning at that position.\n", + " | With optional end, stop comparing S at that position.\n", + " | suffix can also be a tuple of strings to try.\n", + " | \n", + " | expandtabs(...)\n", + " | S.expandtabs(tabsize=8) -> str\n", + " | \n", + " | Return a copy of S where all tab characters are expanded using spaces.\n", + " | If tabsize is not given, a tab size of 8 characters is assumed.\n", + " | \n", + " | find(...)\n", + " | S.find(sub[, start[, end]]) -> int\n", + " | \n", + " | Return the lowest index in S where substring sub is found,\n", + " | such that sub is contained within S[start:end]. Optional\n", + " | arguments start and end are interpreted as in slice notation.\n", + " | \n", + " | Return -1 on failure.\n", + " | \n", + " | format(...)\n", + " | S.format(*args, **kwargs) -> str\n", + " | \n", + " | Return a formatted version of S, using substitutions from args and kwargs.\n", + " | The substitutions are identified by braces ('{' and '}').\n", + " | \n", + " | format_map(...)\n", + " | S.format_map(mapping) -> str\n", + " | \n", + " | Return a formatted version of S, using substitutions from mapping.\n", + " | The substitutions are identified by braces ('{' and '}').\n", + " | \n", + " | index(...)\n", + " | S.index(sub[, start[, end]]) -> int\n", + " | \n", + " | Like S.find() but raise ValueError when the substring is not found.\n", + " | \n", + " | isalnum(...)\n", + " | S.isalnum() -> bool\n", + " | \n", + " | Return True if all characters in S are alphanumeric\n", + " | and there is at least one character in S, False otherwise.\n", + " | \n", + " | isalpha(...)\n", + " | S.isalpha() -> bool\n", + " | \n", + " | Return True if all characters in S are alphabetic\n", + " | and there is at least one character in S, False otherwise.\n", + " | \n", + " | isdecimal(...)\n", + " | S.isdecimal() -> bool\n", + " | \n", + " | Return True if there are only decimal characters in S,\n", + " | False otherwise.\n", + " | \n", + " | isdigit(...)\n", + " | S.isdigit() -> bool\n", + " | \n", + " | Return True if all characters in S are digits\n", + " | and there is at least one character in S, False otherwise.\n", + " | \n", + " | isidentifier(...)\n", + " | S.isidentifier() -> bool\n", + " | \n", + " | Return True if S is a valid identifier according\n", + " | to the language definition.\n", + " | \n", + " | Use keyword.iskeyword() to test for reserved identifiers\n", + " | such as \"def\" and \"class\".\n", + " | \n", + " | islower(...)\n", + " | S.islower() -> bool\n", + " | \n", + " | Return True if all cased characters in S are lowercase and there is\n", + " | at least one cased character in S, False otherwise.\n", + " | \n", + " | isnumeric(...)\n", + " | S.isnumeric() -> bool\n", + " | \n", + " | Return True if there are only numeric characters in S,\n", + " | False otherwise.\n", + " | \n", + " | isprintable(...)\n", + " | S.isprintable() -> bool\n", + " | \n", + " | Return True if all characters in S are considered\n", + " | printable in repr() or S is empty, False otherwise.\n", + " | \n", + " | isspace(...)\n", + " | S.isspace() -> bool\n", + " | \n", + " | Return True if all characters in S are whitespace\n", + " | and there is at least one character in S, False otherwise.\n", + " | \n", + " | istitle(...)\n", + " | S.istitle() -> bool\n", + " | \n", + " | Return True if S is a titlecased string and there is at least one\n", + " | character in S, i.e. upper- and titlecase characters may only\n", + " | follow uncased characters and lowercase characters only cased ones.\n", + " | Return False otherwise.\n", + " | \n", + " | isupper(...)\n", + " | S.isupper() -> bool\n", + " | \n", + " | Return True if all cased characters in S are uppercase and there is\n", + " | at least one cased character in S, False otherwise.\n", + " | \n", + " | join(...)\n", + " | S.join(iterable) -> str\n", + " | \n", + " | Return a string which is the concatenation of the strings in the\n", + " | iterable. The separator between elements is S.\n", + " | \n", + " | ljust(...)\n", + " | S.ljust(width[, fillchar]) -> str\n", + " | \n", + " | Return S left-justified in a Unicode string of length width. Padding is\n", + " | done using the specified fill character (default is a space).\n", + " | \n", + " | lower(...)\n", + " | S.lower() -> str\n", + " | \n", + " | Return a copy of the string S converted to lowercase.\n", + " | \n", + " | lstrip(...)\n", + " | S.lstrip([chars]) -> str\n", + " | \n", + " | Return a copy of the string S with leading whitespace removed.\n", + " | If chars is given and not None, remove characters in chars instead.\n", + " | \n", + " | partition(...)\n", + " | S.partition(sep) -> (head, sep, tail)\n", + " | \n", + " | Search for the separator sep in S, and return the part before it,\n", + " | the separator itself, and the part after it. If the separator is not\n", + " | found, return S and two empty strings.\n", + " | \n", + " | replace(...)\n", + " | S.replace(old, new[, count]) -> str\n", + " | \n", + " | Return a copy of S with all occurrences of substring\n", + " | old replaced by new. If the optional argument count is\n", + " | given, only the first count occurrences are replaced.\n", + " | \n", + " | rfind(...)\n", + " | S.rfind(sub[, start[, end]]) -> int\n", + " | \n", + " | Return the highest index in S where substring sub is found,\n", + " | such that sub is contained within S[start:end]. Optional\n", + " | arguments start and end are interpreted as in slice notation.\n", + " | \n", + " | Return -1 on failure.\n", + " | \n", + " | rindex(...)\n", + " | S.rindex(sub[, start[, end]]) -> int\n", + " | \n", + " | Like S.rfind() but raise ValueError when the substring is not found.\n", + " | \n", + " | rjust(...)\n", + " | S.rjust(width[, fillchar]) -> str\n", + " | \n", + " | Return S right-justified in a string of length width. Padding is\n", + " | done using the specified fill character (default is a space).\n", + " | \n", + " | rpartition(...)\n", + " | S.rpartition(sep) -> (head, sep, tail)\n", + " | \n", + " | Search for the separator sep in S, starting at the end of S, and return\n", + " | the part before it, the separator itself, and the part after it. If the\n", + " | separator is not found, return two empty strings and S.\n", + " | \n", + " | rsplit(...)\n", + " | S.rsplit(sep=None, maxsplit=-1) -> list of strings\n", + " | \n", + " | Return a list of the words in S, using sep as the\n", + " | delimiter string, starting at the end of the string and\n", + " | working to the front. If maxsplit is given, at most maxsplit\n", + " | splits are done. If sep is not specified, any whitespace string\n", + " | is a separator.\n", + " | \n", + " | rstrip(...)\n", + " | S.rstrip([chars]) -> str\n", + " | \n", + " | Return a copy of the string S with trailing whitespace removed.\n", + " | If chars is given and not None, remove characters in chars instead.\n", + " | \n", + " | split(...)\n", + " | S.split(sep=None, maxsplit=-1) -> list of strings\n", + " | \n", + " | Return a list of the words in S, using sep as the\n", + " | delimiter string. If maxsplit is given, at most maxsplit\n", + " | splits are done. If sep is not specified or is None, any\n", + " | whitespace string is a separator and empty strings are\n", + " | removed from the result.\n", + " | \n", + " | splitlines(...)\n", + " | S.splitlines([keepends]) -> list of strings\n", + " | \n", + " | Return a list of the lines in S, breaking at line boundaries.\n", + " | Line breaks are not included in the resulting list unless keepends\n", + " | is given and true.\n", + " | \n", + " | startswith(...)\n", + " | S.startswith(prefix[, start[, end]]) -> bool\n", + " | \n", + " | Return True if S starts with the specified prefix, False otherwise.\n", + " | With optional start, test S beginning at that position.\n", + " | With optional end, stop comparing S at that position.\n", + " | prefix can also be a tuple of strings to try.\n", + " | \n", + " | strip(...)\n", + " | S.strip([chars]) -> str\n", + " | \n", + " | Return a copy of the string S with leading and trailing\n", + " | whitespace removed.\n", + " | If chars is given and not None, remove characters in chars instead.\n", + " | \n", + " | swapcase(...)\n", + " | S.swapcase() -> str\n", + " | \n", + " | Return a copy of S with uppercase characters converted to lowercase\n", + " | and vice versa.\n", + " | \n", + " | title(...)\n", + " | S.title() -> str\n", + " | \n", + " | Return a titlecased version of S, i.e. words start with title case\n", + " | characters, all remaining cased characters have lower case.\n", + " | \n", + " | translate(...)\n", + " | S.translate(table) -> str\n", + " | \n", + " | Return a copy of the string S in which each character has been mapped\n", + " | through the given translation table. The table must implement\n", + " | lookup/indexing via __getitem__, for instance a dictionary or list,\n", + " | mapping Unicode ordinals to Unicode ordinals, strings, or None. If\n", + " | this operation raises LookupError, the character is left untouched.\n", + " | Characters mapped to None are deleted.\n", + " | \n", + " | upper(...)\n", + " | S.upper() -> str\n", + " | \n", + " | Return a copy of S converted to uppercase.\n", + " | \n", + " | zfill(...)\n", + " | S.zfill(width) -> str\n", + " | \n", + " | Pad a numeric string S with zeros on the left, to fill a field\n", + " | of the specified width. The string S is never truncated.\n", + " | \n", + " | ----------------------------------------------------------------------\n", + " | Static methods defined here:\n", + " | \n", + " | maketrans(x, y=None, z=None, /)\n", + " | Return a translation table usable for str.translate().\n", + " | \n", + " | If there is only one argument, it must be a dictionary mapping Unicode\n", + " | ordinals (integers) or characters to Unicode ordinals, strings or None.\n", + " | Character keys will be then converted to ordinals.\n", + " | If there are two arguments, they must be strings of equal length, and\n", + " | in the resulting dictionary, each character in x will be mapped to the\n", + " | character at the same position in y. If there is a third argument, it\n", + " | must be a string, whose characters will be mapped to None in the result.\n", + "\n" + ] }, { - "cell_type": "code", - "collapsed": false, - "input": [ - "def possible_flavors():\n", - " return [\"up\", \"down\", \"top\", \"bottom\", \"strange\", \"charm\"]" - ], - "language": "python", + "data": { + "text/plain": [ + "['__add__',\n", + " '__class__',\n", + " '__contains__',\n", + " '__delattr__',\n", + " '__dir__',\n", + " '__doc__',\n", + " '__eq__',\n", + " '__format__',\n", + " '__ge__',\n", + " '__getattribute__',\n", + " '__getitem__',\n", + " '__getnewargs__',\n", + " '__gt__',\n", + " '__hash__',\n", + " '__init__',\n", + " '__iter__',\n", + " '__le__',\n", + " '__len__',\n", + " '__lt__',\n", + " '__mod__',\n", + " '__mul__',\n", + " '__ne__',\n", + " '__new__',\n", + " '__reduce__',\n", + " '__reduce_ex__',\n", + " '__repr__',\n", + " '__rmod__',\n", + " '__rmul__',\n", + " '__setattr__',\n", + " '__sizeof__',\n", + " '__str__',\n", + " '__subclasshook__',\n", + " 'capitalize',\n", + " 'casefold',\n", + " 'center',\n", + " 'count',\n", + " 'encode',\n", + " 'endswith',\n", + " 'expandtabs',\n", + " 'find',\n", + " 'format',\n", + " 'format_map',\n", + " 'index',\n", + " 'isalnum',\n", + " 'isalpha',\n", + " 'isdecimal',\n", + " 'isdigit',\n", + " 'isidentifier',\n", + " 'islower',\n", + " 'isnumeric',\n", + " 'isprintable',\n", + " 'isspace',\n", + " 'istitle',\n", + " 'isupper',\n", + " 'join',\n", + " 'ljust',\n", + " 'lower',\n", + " 'lstrip',\n", + " 'maketrans',\n", + " 'partition',\n", + " 'replace',\n", + " 'rfind',\n", + " 'rindex',\n", + " 'rjust',\n", + " 'rpartition',\n", + " 'rsplit',\n", + " 'rstrip',\n", + " 'split',\n", + " 'splitlines',\n", + " 'startswith',\n", + " 'strip',\n", + " 'swapcase',\n", + " 'title',\n", + " 'translate',\n", + " 'upper',\n", + " 'zfill']" + ] + }, + "execution_count": 16, "metadata": {}, - "outputs": [], - "prompt_number": 22 - }, + "output_type": "execute_result" + } + ], + "source": [ + "a = ' '\n", + "help(a)\n", + "dir(a)" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "collapsed": false, - "input": [ - "from scipy import constants\n", - "\n", - "def possible_flavors():\n", - " return[\"up\",\"down\",\"top\",\"bottom\",\"strange\",\"charm\"]\n", - "\n", - "class Particle(object):\n", - " \"\"\"A particle is a constituent unit of the universe.\"\"\"\n", - "\n", - " # ... other parts of the class definition ...\n", + "name": "stdout", + "output_type": "stream", + "text": [ + "Help on float object:\n", "\n", - " def delta_x_min(self, delta_p_x):\n", - " hbar = constants.hbar\n", - " delx_min = hbar / (2.0 * delta_p_x)\n", - " return delx_min\n", - "\n", - " @staticmethod\n", - " def possible_flavors():\n", - " return [\"up\", \"down\", \"top\", \"bottom\", \"strange\", \"charm\"]" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 23 + "class float(object)\n", + " | float(x) -> floating point number\n", + " | \n", + " | Convert a string or number to a floating point number, if possible.\n", + " | \n", + " | Methods defined here:\n", + " | \n", + " | __abs__(self, /)\n", + " | abs(self)\n", + " | \n", + " | __add__(self, value, /)\n", + " | Return self+value.\n", + " | \n", + " | __bool__(self, /)\n", + " | self != 0\n", + " | \n", + " | __divmod__(self, value, /)\n", + " | Return divmod(self, value).\n", + " | \n", + " | __eq__(self, value, /)\n", + " | Return self==value.\n", + " | \n", + " | __float__(self, /)\n", + " | float(self)\n", + " | \n", + " | __floordiv__(self, value, /)\n", + " | Return self//value.\n", + " | \n", + " | __format__(...)\n", + " | float.__format__(format_spec) -> string\n", + " | \n", + " | Formats the float according to format_spec.\n", + " | \n", + " | __ge__(self, value, /)\n", + " | Return self>=value.\n", + " | \n", + " | __getattribute__(self, name, /)\n", + " | Return getattr(self, name).\n", + " | \n", + " | __getformat__(...) from builtins.type\n", + " | float.__getformat__(typestr) -> string\n", + " | \n", + " | You probably don't want to use this function. It exists mainly to be\n", + " | used in Python's test suite.\n", + " | \n", + " | typestr must be 'double' or 'float'. This function returns whichever of\n", + " | 'unknown', 'IEEE, big-endian' or 'IEEE, little-endian' best describes the\n", + " | format of floating point numbers used by the C type named by typestr.\n", + " | \n", + " | __getnewargs__(...)\n", + " | \n", + " | __gt__(self, value, /)\n", + " | Return self>value.\n", + " | \n", + " | __hash__(self, /)\n", + " | Return hash(self).\n", + " | \n", + " | __int__(self, /)\n", + " | int(self)\n", + " | \n", + " | __le__(self, value, /)\n", + " | Return self<=value.\n", + " | \n", + " | __lt__(self, value, /)\n", + " | Return self None\n", + " | \n", + " | You probably don't want to use this function. It exists mainly to be\n", + " | used in Python's test suite.\n", + " | \n", + " | typestr must be 'double' or 'float'. fmt must be one of 'unknown',\n", + " | 'IEEE, big-endian' or 'IEEE, little-endian', and in addition can only be\n", + " | one of the latter two if it appears to match the underlying C reality.\n", + " | \n", + " | Override the automatic determination of C-level floating point type.\n", + " | This affects how floats are converted to and from binary strings.\n", + " | \n", + " | __str__(self, /)\n", + " | Return str(self).\n", + " | \n", + " | __sub__(self, value, /)\n", + " | Return self-value.\n", + " | \n", + " | __truediv__(self, value, /)\n", + " | Return self/value.\n", + " | \n", + " | __trunc__(...)\n", + " | Return the Integral closest to x between 0 and x.\n", + " | \n", + " | as_integer_ratio(...)\n", + " | float.as_integer_ratio() -> (int, int)\n", + " | \n", + " | Return a pair of integers, whose ratio is exactly equal to the original\n", + " | float and with a positive denominator.\n", + " | Raise OverflowError on infinities and a ValueError on NaNs.\n", + " | \n", + " | >>> (10.0).as_integer_ratio()\n", + " | (10, 1)\n", + " | >>> (0.0).as_integer_ratio()\n", + " | (0, 1)\n", + " | >>> (-.25).as_integer_ratio()\n", + " | (-1, 4)\n", + " | \n", + " | conjugate(...)\n", + " | Return self, the complex conjugate of any float.\n", + " | \n", + " | fromhex(...) from builtins.type\n", + " | float.fromhex(string) -> float\n", + " | \n", + " | Create a floating-point number from a hexadecimal string.\n", + " | >>> float.fromhex('0x1.ffffp10')\n", + " | 2047.984375\n", + " | >>> float.fromhex('-0x1p-1074')\n", + " | -5e-324\n", + " | \n", + " | hex(...)\n", + " | float.hex() -> string\n", + " | \n", + " | Return a hexadecimal representation of a floating-point number.\n", + " | >>> (-0.1).hex()\n", + " | '-0x1.999999999999ap-4'\n", + " | >>> 3.14159.hex()\n", + " | '0x1.921f9f01b866ep+1'\n", + " | \n", + " | is_integer(...)\n", + " | Return True if the float is an integer.\n", + " | \n", + " | ----------------------------------------------------------------------\n", + " | Data descriptors defined here:\n", + " | \n", + " | imag\n", + " | the imaginary part of a complex number\n", + " | \n", + " | real\n", + " | the real part of a complex number\n", + "\n" + ] }, { - "cell_type": "code", - "collapsed": false, - "input": [ - "def total_charge(particles):\n", - " tot = 0\n", - " for p in particles:\n", - " tot += p.c\n", - " return tot" - ], - "language": "python", + "data": { + "text/plain": [ + "['__abs__',\n", + " '__add__',\n", + " '__bool__',\n", + " '__class__',\n", + " '__delattr__',\n", + " '__dir__',\n", + " '__divmod__',\n", + " '__doc__',\n", + " '__eq__',\n", + " '__float__',\n", + " '__floordiv__',\n", + " '__format__',\n", + " '__ge__',\n", + " '__getattribute__',\n", + " '__getformat__',\n", + " '__getnewargs__',\n", + " '__gt__',\n", + " '__hash__',\n", + " '__init__',\n", + " '__int__',\n", + " '__le__',\n", + " '__lt__',\n", + " '__mod__',\n", + " '__mul__',\n", + " '__ne__',\n", + " '__neg__',\n", + " '__new__',\n", + " '__pos__',\n", + " '__pow__',\n", + " '__radd__',\n", + " '__rdivmod__',\n", + " '__reduce__',\n", + " '__reduce_ex__',\n", + " '__repr__',\n", + " '__rfloordiv__',\n", + " '__rmod__',\n", + " '__rmul__',\n", + " '__round__',\n", + " '__rpow__',\n", + " '__rsub__',\n", + " '__rtruediv__',\n", + " '__setattr__',\n", + " '__setformat__',\n", + " '__sizeof__',\n", + " '__str__',\n", + " '__sub__',\n", + " '__subclasshook__',\n", + " '__truediv__',\n", + " '__trunc__',\n", + " 'as_integer_ratio',\n", + " 'conjugate',\n", + " 'fromhex',\n", + " 'hex',\n", + " 'imag',\n", + " 'is_integer',\n", + " 'real']" + ] + }, + "execution_count": 18, "metadata": {}, - "outputs": [], - "prompt_number": 24 - }, + "output_type": "execute_result" + } + ], + "source": [ + "a = 3.14\n", + "help(a)\n", + "dir(a)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Functions are objects too, and we can use the dir() function on them to learn more." + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "collapsed": false, - "input": [ - "def total_charge(collection):\n", - " tot = 0\n", - " for p in collection:\n", - " if isinstance(p, Particle):\n", - " tot += p.c\n", - " return tot" - ], - "language": "python", + "data": { + "text/plain": [ + "['__call__',\n", + " '__class__',\n", + " '__delattr__',\n", + " '__dir__',\n", + " '__doc__',\n", + " '__eq__',\n", + " '__format__',\n", + " '__ge__',\n", + " '__getattribute__',\n", + " '__gt__',\n", + " '__hash__',\n", + " '__init__',\n", + " '__le__',\n", + " '__lt__',\n", + " '__module__',\n", + " '__name__',\n", + " '__ne__',\n", + " '__new__',\n", + " '__qualname__',\n", + " '__reduce__',\n", + " '__reduce_ex__',\n", + " '__repr__',\n", + " '__self__',\n", + " '__setattr__',\n", + " '__sizeof__',\n", + " '__str__',\n", + " '__subclasshook__',\n", + " '__text_signature__']" + ] + }, + "execution_count": 19, "metadata": {}, - "outputs": [], - "prompt_number": 25 - }, + "output_type": "execute_result" + } + ], + "source": [ + "import math\n", + "dir(math.sin)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can access the docstrings of a function with the \\__docs__ methods" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "collapsed": false, - "input": [ - "# elementary.py\n", - "class ElementaryParticle(Particle):\n", - "\n", - " def __init__(self, spin):\n", - " self.s = spin\n", - " self.is_fermion = bool(spin % 1.0)\n", - " self.is_boson = not self.is_fermion" - ], - "language": "python", + "data": { + "text/plain": [ + "'sin(x)\\n\\nReturn the sine of x (measured in radians).'" + ] + }, + "execution_count": 21, "metadata": {}, - "outputs": [], - "prompt_number": 26 - }, + "output_type": "execute_result" + } + ], + "source": [ + "import math \n", + "math.sin.__doc__" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The docstring is also an object, check this out:" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "collapsed": false, - "input": [ - "# composite.py\n", - "class CompositeParticle(Particle):\n", - "\n", - " def __init__(self, parts):\n", - " self.constituents = parts" - ], - "language": "python", + "data": { + "text/plain": [ + "['__add__',\n", + " '__class__',\n", + " '__contains__',\n", + " '__delattr__',\n", + " '__dir__',\n", + " '__doc__',\n", + " '__eq__',\n", + " '__format__',\n", + " '__ge__',\n", + " '__getattribute__',\n", + " '__getitem__',\n", + " '__getnewargs__',\n", + " '__gt__',\n", + " '__hash__',\n", + " '__init__',\n", + " '__iter__',\n", + " '__le__',\n", + " '__len__',\n", + " '__lt__',\n", + " '__mod__',\n", + " '__mul__',\n", + " '__ne__',\n", + " '__new__',\n", + " '__reduce__',\n", + " '__reduce_ex__',\n", + " '__repr__',\n", + " '__rmod__',\n", + " '__rmul__',\n", + " '__setattr__',\n", + " '__sizeof__',\n", + " '__str__',\n", + " '__subclasshook__',\n", + " 'capitalize',\n", + " 'casefold',\n", + " 'center',\n", + " 'count',\n", + " 'encode',\n", + " 'endswith',\n", + " 'expandtabs',\n", + " 'find',\n", + " 'format',\n", + " 'format_map',\n", + " 'index',\n", + " 'isalnum',\n", + " 'isalpha',\n", + " 'isdecimal',\n", + " 'isdigit',\n", + " 'isidentifier',\n", + " 'islower',\n", + " 'isnumeric',\n", + " 'isprintable',\n", + " 'isspace',\n", + " 'istitle',\n", + " 'isupper',\n", + " 'join',\n", + " 'ljust',\n", + " 'lower',\n", + " 'lstrip',\n", + " 'maketrans',\n", + " 'partition',\n", + " 'replace',\n", + " 'rfind',\n", + " 'rindex',\n", + " 'rjust',\n", + " 'rpartition',\n", + " 'rsplit',\n", + " 'rstrip',\n", + " 'split',\n", + " 'splitlines',\n", + " 'startswith',\n", + " 'strip',\n", + " 'swapcase',\n", + " 'title',\n", + " 'translate',\n", + " 'upper',\n", + " 'zfill']" + ] + }, + "execution_count": 23, "metadata": {}, - "outputs": [], - "prompt_number": 27 - }, + "output_type": "execute_result" + } + ], + "source": [ + "dir(math.sin.__doc__)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Classes \n", + "\n", + "Classes serve many roles. Classes define the collection of attributes that describe a type of object. They also describe how to create that type of object and may inherit attributes from other classes hierarchically.\n", + "\n", + "The following cells are examples of classes we would create during a particle physics simulation:" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [], + "source": [ + "class Particle(object): # Begins the class definition and names the class particle\n", + " \"\"\"A particle is a constituent unit of the universe.\"\"\" # A docstring for the class \n", + " # class body definition here" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Class variables\n", + "\n", + "Many attributes should be included in the class definition. The first of these that we will introduce is the class variable. Class variables are data that are applicable to every object of the class. For example, in our particles class, every object should be able to say \"I am a particle.\" We can then set a class-level atrribute equal to the string \"I am a particle\" " + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": {}, + "outputs": [], + "source": [ + "# particle.py\n", + "class Particle(object):\n", + " \"\"\"A particle is a constituent unit of the universe.\"\"\"\n", + " roar = \"I am a particle!\" " + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import sys\n", + "sys.path.insert(0, os.path.abspath('obj'))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can access class variables even without declaring an instance of the class, as in the following code:" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "collapsed": false, - "input": [ - "# elementary.py\n", - "class ElementaryParticle(Particle):\n", - "\n", - " roar = \"I am an Elementary Particle!\"\n", - "\n", - " def __init__(self, spin):\n", - " self.s = spin\n", - " self.is_fermion = bool(spin % 1.0)\n", - " self.is_boson = not self.is_fermion" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 28 - }, + "name": "stdout", + "output_type": "stream", + "text": [ + "I am a particle!\n" + ] + } + ], + "source": [ + "# import the particle module\n", + "import particle as p\n", + "print(p.Particle.roar)" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "collapsed": false, - "input": [ - "from elementary import ElementaryParticle\n", - "\n", - "spin = 1.5\n", - "p = ElementaryParticle(spin)\n", - "p.s\n", - "p.hear_me()" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "ename": "AttributeError", - "evalue": "'ElementaryParticle' object has no attribute 'm'", - "output_type": "pyerr", - "traceback": [ - "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[1;31mAttributeError\u001b[0m Traceback (most recent call last)", - "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[0;32m 4\u001b[0m \u001b[0mp\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mElementaryParticle\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mspin\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 5\u001b[0m \u001b[0mp\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0ms\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 6\u001b[1;33m \u001b[0mp\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mhear_me\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", - "\u001b[1;32m/home/scopatz/physics-codes-examples/obj/particle.py\u001b[0m in \u001b[0;36mhear_me\u001b[1;34m(self)\u001b[0m\n\u001b[0;32m 13\u001b[0m \u001b[1;34m\" My x position is: \"\u001b[0m \u001b[1;33m+\u001b[0m \u001b[0mstr\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mr\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;34m'x'\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;33m+\u001b[0m\u001b[1;34m\"\\n\"\u001b[0m\u001b[1;33m+\u001b[0m\u001b[0;31m\\\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 14\u001b[0m \u001b[1;34m\" My y position is: \"\u001b[0m \u001b[1;33m+\u001b[0m \u001b[0mstr\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mr\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;34m'y'\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;33m+\u001b[0m\u001b[1;34m\"\\n\"\u001b[0m\u001b[1;33m+\u001b[0m\u001b[0;31m\\\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 15\u001b[1;33m \u001b[1;34m\" My z position is: \"\u001b[0m \u001b[1;33m+\u001b[0m \u001b[0mstr\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mr\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;34m'z'\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 16\u001b[0m \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mmyroar\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 17\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n", - "\u001b[1;31mAttributeError\u001b[0m: 'ElementaryParticle' object has no attribute 'm'" - ] - } - ], - "prompt_number": 29 - }, + "name": "stdout", + "output_type": "stream", + "text": [ + "I am a particle!\n" + ] + } + ], + "source": [ + "# import the particle module\n", + "import particle as p\n", + "higgs = p.Particle()\n", + "print(higgs.roar)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Instance Variables\n", + "\n", + "Some variables should only apply to certain objects in the class. These are called \"instance variables.\" For example, every particle should have its own position vector. A rather clumsy way to assign position vectors to all of the objects in the particle class is demonstrated in the following cell:" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "collapsed": false, - "input": [ - "import randphys as rp\n", - "\n", - "class Quark(ElementaryParticle):\n", - "\n", - " def __init__(self):\n", - " phys = rp.RandomPhysics()\n", - " self.color = phys.color()\n", - " self.charge = phys.charge()\n", - " self.color_charge = phys.color_charge()\n", - " self.spin = phys.spin()\n", - " self.flavor = phys.flavor()" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 30 - }, + "name": "stdout", + "output_type": "stream", + "text": [ + "{'x': 100.0, 'z': -42.0, 'y': 38.0}\n", + "{'x': 0.01, 'z': 32.0, 'y': 99.0}\n" + ] + } + ], + "source": [ + "# import the Particle class from the particle module\n", + "from particle import Particle\n", + "\n", + "# create an empty list to hold observed particle data\n", + "obs = []\n", + "\n", + "# append the first particle\n", + "obs.append(Particle())\n", + "\n", + "# assign its position\n", + "obs[0].r = {'x': 100.0, 'y': 38.0, 'z': -42.0}\n", + "\n", + "# append the second particle\n", + "obs.append(Particle())\n", + "\n", + "# assign the position of the second particle\n", + "obs[1].r = {'x': 0.01, 'y': 99.0, 'z': 32.0}\n", + "\n", + "# print the positions of each particle\n", + "print(obs[0].r)\n", + "print(obs[1].r)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Constructors\n", + "\n", + "Constructors allow us to associate data attributes with a specific instance of a class. Whenever an object is created as part of a class, the constructor function, which is always named `\\__init__()`, is executed. \n", + "\n", + "The next example defines a constructor function that assigns values of charge, mass, and position to the particle.\n", + "\n", + "Note that `\\__init__()` always takes `self ` as an argument. The other paramters are assigned with the syntax `self. = `" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": {}, + "outputs": [], + "source": [ + "# particle.py\n", + "class Particle(object):\n", + " \"\"\"A particle is a constituent unit of the universe.\n", + " \n", + " Attributes\n", + " ----------\n", + " c : charge in units of [e]\n", + " m : mass in units of [kg]\n", + " r : position in units of [meters]\n", + " \"\"\"\n", + "\n", + " roar = \"I am a particle!\"\n", + "\n", + " def __init__(self):\n", + " \"\"\"Initializes the particle with default values for \n", + " charge c, mass m, and position r.\n", + " \"\"\"\n", + " self.c = 0\n", + " self.m = 0\n", + " self.r = {'x': 0, 'y': 0, 'z': 0}\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The constructor can be made for powerful by passing arguments to it, as in this example:" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": {}, + "outputs": [], + "source": [ + "# particle.py\n", + "class Particle(object):\n", + " \"\"\"A particle is a constituent unit of the universe.\n", + " \n", + " Attributes\n", + " ----------\n", + " c : charge in units of [e]\n", + " m : mass in units of [kg]\n", + " r : position in units of [meters]\n", + " \"\"\"\n", + "\n", + " roar = \"I am a particle!\"\n", + "\n", + " def __init__(self, charge, mass, position): # Self is the first argument, followed by three positional arguments\n", + " \"\"\"Initializes the particle with supplied values for \n", + " charge c, mass m, and position r.\n", + " \"\"\"\n", + " self.c = charge # C is introduced and assigned to self with the value provided in the method call\n", + " self.m = mass\n", + " self.r = position\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Methods\n", + "\n", + "We have discussed methods a bit without formally introducing them. Methods are a special type of function that is associated with a class defintion. Methods may be used to operate on data contained by the object, as in these examples:" + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "metadata": {}, + "outputs": [], + "source": [ + "# particle.py\n", + "class Particle(object):\n", + " \"\"\"A particle is a constituent unit of the universe.\n", + " \n", + " Attributes\n", + " ----------\n", + " c : charge in units of [e]\n", + " m : mass in units of [kg]\n", + " r : position in units of [meters]\n", + " \"\"\"\n", + "\n", + " roar = \"I am a particle!\"\n", + "\n", + " def __init__(self, charge, mass, position): \n", + " \"\"\"Initializes the particle with supplied values for \n", + " charge c, mass m, and position r.\n", + " \"\"\"\n", + " self.c = charge\n", + " self.m = mass\n", + " self.r = position\n", + "\n", + " def hear_me(self): # The object and all of its data are passed to the method as self\n", + " myroar = self.roar + (\n", + " \" My charge is: \" + str(self.c) + # The self argument is used to access the instance variable c\n", + " \" My mass is: \" + str(self.m) +\n", + " \" My x position is: \" + str(self.r['x']) +\n", + " \" My y position is: \" + str(self.r['y']) +\n", + " \" My z position is: \" + str(self.r['z']))\n", + " print(myroar)" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "metadata": { + "scrolled": true + }, + "outputs": [ { - "cell_type": "code", - "collapsed": false, - "input": [ - "def add_is_particle(cls): <1>\n", - " cls.is_particle = True <2>\n", - " return cls <3>\n", - "\n", - "\n", - "@add_is_particle <4>\n", - "class Particle(object):\n", - " \"\"\"A particle is a constituent unit of the universe.\"\"\"\n", - "\n", - " # ... other parts of the class definition ..." - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "ename": "SyntaxError", - "evalue": "invalid syntax (, line 1)", - "output_type": "pyerr", - "traceback": [ - "\u001b[1;36m File \u001b[1;32m\"\"\u001b[1;36m, line \u001b[1;32m1\u001b[0m\n\u001b[1;33m def add_is_particle(cls): <1>\u001b[0m\n\u001b[1;37m ^\u001b[0m\n\u001b[1;31mSyntaxError\u001b[0m\u001b[1;31m:\u001b[0m invalid syntax\n" - ] - } - ], - "prompt_number": 31 - }, + "name": "stdout", + "output_type": "stream", + "text": [ + "I am a particle!\n", + " My mass is: 1.672621898e-27\n", + " My charge is: 1\n", + " My x position is: 1\n", + " My y position is: 1\n", + " My z position is: 53\n" + ] + } + ], + "source": [ + "from scipy import constants\n", + "\n", + "import particle as p\n", + "\n", + "m_p = constants.m_p\n", + "r_p = {'x': 1, 'y': 1, 'z': 53}\n", + "a_p = p.Particle(1, m_p, r_p)\n", + "a_p.hear_me()" + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "collapsed": false, - "input": [ - "from math import sqrt\n", - "\n", - "def add_distance(cls):\n", - " def distance(self, other): \n", - " d2 = 0.0\n", - " for axis in ['x', 'y', 'z']:\n", - " d2 += (self.r[axis] - other.r[axis])**2\n", - " d = sqrt(d2)\n", - " return d\n", - " cls.distance = distance\n", - " return cls \n", - "\n", - "\n", - "@add_distance\n", - "class Particle(object):\n", - " \"\"\"A particle is a constituent unit of the universe.\"\"\"\n", - "\n", - " # ... other parts of the class definition ..." - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 32 - }, + "name": "stdout", + "output_type": "stream", + "text": [ + "I am a particle!\n", + " My mass is: 9.10938356e-31\n", + " My charge is: -1\n", + " My x position is: 11\n", + " My y position is: 1\n", + " My z position is: 53\n" + ] + } + ], + "source": [ + "from scipy import constants\n", + "\n", + "import particle as e\n", + "\n", + "m_e = constants.m_e\n", + "r_e = {'x': 11, 'y': 1, 'z': 53}\n", + "a_e = p.Particle(-1, m_e, r_e)\n", + "a_e.hear_me()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The next example creates a `flip` method that changes a quark's flavor while maintaining symmetry" + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "metadata": {}, + "outputs": [], + "source": [ + "def flip(self):\n", + " if self.flavor == \"up\":\n", + " self.flavor = \"down\"\n", + " elif self.flavor == \"down\":\n", + " self.flavor = \"up\"\n", + " elif self.flavor == \"top\":\n", + " self.flavor = \"bottom\"\n", + " elif self.flavor == \"bottom\":\n", + " self.flavor = \"top\"\n", + " elif self.flavor == \"strange\":\n", + " self.flavor = \"charm\"\n", + " elif self.flavor == \"charm\":\n", + " self.flavor = \"strange\"\n", + " else :\n", + " raise AttributeError(\"The quark cannot be flipped, because the \"\n", + " \"flavor is not valid.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Here is our method in action, changing the attributes of an object after it is called:" + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "collapsed": false, - "input": [ - "type(type)" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 33, - "text": [ - "type" - ] - } - ], - "prompt_number": 33 - }, + "name": "stdout", + "output_type": "stream", + "text": [ + "bottom\n" + ] + } + ], + "source": [ + "# import the class\n", + "from quark import Quark\n", + "\n", + "# create a Quark object\n", + "t = Quark()\n", + "\n", + "# set the flavor\n", + "t.flavor = \"top\"\n", + "\n", + "# flip the flavor\n", + "t.flip()\n", + "\n", + "# print the flavor\n", + "print(t.flavor)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Another powerful method that we could add to the `Particles` class uses the Heisenberg principle to determine the minimum uncertainty in position, given an uncertainty in momentum" + ] + }, + { + "cell_type": "code", + "execution_count": 48, + "metadata": {}, + "outputs": [], + "source": [ + "from scipy import constants\n", + "\n", + "class Particle(object):\n", + " \"\"\"A particle is a constituent unit of the universe.\"\"\"\n", + "\n", + " # ... other parts of the class definition ...\n", + "\n", + " def delta_x_min(self, delta_p_x):\n", + " hbar = constants.hbar\n", + " delx_min = hbar / (2.0 * delta_p_x)\n", + " return delx_min" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Static Methods\n", + "\n", + "We can add a method that behaves the same for every instance. Consider a function that lists the possible quark flavors. This list does not depend on the flavor of the quark. Such a function could like the following:" + ] + }, + { + "cell_type": "code", + "execution_count": 51, + "metadata": {}, + "outputs": [], + "source": [ + "def possible_flavors():\n", + " return [\"up\", \"down\", \"top\", \"bottom\", \"strange\", \"charm\"]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can add this function as a method of a class by using python's built-in `@staticmethod` decorator so that the method does not take any arguments, and behaves the same for all objects in the class." + ] + }, + { + "cell_type": "code", + "execution_count": 53, + "metadata": {}, + "outputs": [], + "source": [ + "from scipy import constants\n", + "\n", + "def possible_flavors():\n", + " return[\"up\",\"down\",\"top\",\"bottom\",\"strange\",\"charm\"]\n", + "\n", + "class Particle(object):\n", + " \"\"\"A particle is a constituent unit of the universe.\"\"\"\n", + "\n", + " # ... other parts of the class definition ...\n", + "\n", + " def delta_x_min(self, delta_p_x):\n", + " hbar = constants.hbar\n", + " delx_min = hbar / (2.0 * delta_p_x)\n", + " return delx_min\n", + "\n", + " @staticmethod\n", + " def possible_flavors():\n", + " return [\"up\", \"down\", \"top\", \"bottom\", \"strange\", \"charm\"]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Duck Typing\n", + "\n", + "Duck typing was introduced in Chapter 3. We will explore it in more detail here. Duck typing refers to Python's tactic of only checking the types of an object that are relevant to its use at the time of its use. \n", + "Thus, any particles with a valid `Charge()` method may be used identically, as in this example:" + ] + }, + { + "cell_type": "code", + "execution_count": 70, + "metadata": {}, + "outputs": [], + "source": [ + "def total_charge(particles):\n", + " tot = 0\n", + " for p in particles:\n", + " tot += p.c\n", + " return tot" + ] + }, + { + "cell_type": "code", + "execution_count": 78, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "collapsed": false, - "input": [ - "class IsParticle(type):\n", - " pass" - ], - "language": "python", + "data": { + "text/plain": [ + "-1" + ] + }, + "execution_count": 78, "metadata": {}, - "outputs": [], - "prompt_number": 34 - }, + "output_type": "execute_result" + } + ], + "source": [ + "p = a_p\n", + "e1 = a_e\n", + "e2 = a_e\n", + "\n", + "particles = [p, e1, e2]\n", + "total_charge(particles)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Sometimes duck typing is undesirable. The isinstance() function can be used with an if statement to ensure only objects of a certain type are passed to a method" + ] + }, + { + "cell_type": "code", + "execution_count": 80, + "metadata": {}, + "outputs": [], + "source": [ + "def total_charge(collection):\n", + " tot = 0\n", + " for p in collection:\n", + " if isinstance(p, Particle):\n", + " tot += p.c\n", + " return tot" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Polymorphism\n", + "\n", + "Polymorphism occurs when a class inherits the attributes of a parent class. Generally, what works for a parent class should also work for the subclass, but the subclass should be able to execute its own specialized behavior as well. \n", + "\n", + "Consider a subclass of `particles` that describes elementary particles such as electrons, quarks, and muons. Such a class might contain a method that checks a particle's spin, and names the particle as a fermion when it has non-integer spin, and a boson when it has integer spin. This subclass is written below:" + ] + }, + { + "cell_type": "code", + "execution_count": 83, + "metadata": {}, + "outputs": [], + "source": [ + "# elementary.py\n", + "class ElementaryParticle(Particle):\n", + "\n", + " def __init__(self, spin):\n", + " self.s = spin\n", + " self.is_fermion = bool(spin % 1.0)\n", + " self.is_boson = not self.is_fermion" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "It seems that `ElementaryParticle` takes `Particle` as an argument. This syntax establishes `Particle` as the parent class to `ElementaryParticle`, following the inheritance diagram in figure 6-2 on page 136. \n", + "\n", + "Another subclass of `Particle` could be `CompositeParticle`. This class may have all the properties of the `Particle` class, as well as a list of its constituents. The only properties it shares with the `ElementaryParticle` class are those inherited from `Particle`." + ] + }, + { + "cell_type": "code", + "execution_count": 87, + "metadata": {}, + "outputs": [], + "source": [ + "# composite.py\n", + "class CompositeParticle(Particle):\n", + "\n", + " def __init__(self, parts):\n", + " self.constituents = parts" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Subclasses\n", + "\n", + "Objects in the `ElementaryParticle` class and in the `CompositeParticle` class __are__ in the the `Particle` class because those classes inherit from `Particle`. Inheritance has thus allowed us to reuse code without any rewriting. \n", + "\n", + "However, the behavior from `Particle` can be overwritten, as in the following example:" + ] + }, + { + "cell_type": "code", + "execution_count": 88, + "metadata": {}, + "outputs": [], + "source": [ + "# elementary.py\n", + "class ElementaryParticle(Particle):\n", + "\n", + " roar = \"I am an Elementary Particle!\"\n", + "\n", + " def __init__(self, spin):\n", + " self.s = spin\n", + " self.is_fermion = bool(spin % 1.0)\n", + " self.is_boson = not self.is_fermion" + ] + }, + { + "cell_type": "code", + "execution_count": 103, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "collapsed": false, - "input": [ - "class Particle(metaclass=IsParticle):\n", - " \"\"\"A particle is a constituent unit of the universe.\"\"\"\n", - "\n", - " # ... other parts of the class definition ..." - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 35 - }, + "ename": "AttributeError", + "evalue": "'ElementaryParticle' object has no attribute 'm'", + "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[1;32m 4\u001b[0m \u001b[0mp\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mElementaryParticle\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mspin\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0mp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0ms\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 6\u001b[0;31m \u001b[0mp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mhear_me\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m~/Documents/husc/examples/obj/particle.py\u001b[0m in \u001b[0;36mhear_me\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m 13\u001b[0m \u001b[0;34m\" My x position is: \"\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0mstr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mr\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'x'\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m+\u001b[0m\u001b[0;34m\"\\n\"\u001b[0m\u001b[0;34m+\u001b[0m\u001b[0;31m\\\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 14\u001b[0m \u001b[0;34m\" My y position is: \"\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0mstr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mr\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'y'\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m+\u001b[0m\u001b[0;34m\"\\n\"\u001b[0m\u001b[0;34m+\u001b[0m\u001b[0;31m\\\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 15\u001b[0;31m \u001b[0;34m\" My z position is: \"\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0mstr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mr\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'z'\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 16\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mmyroar\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 17\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mAttributeError\u001b[0m: 'ElementaryParticle' object has no attribute 'm'" + ] + } + ], + "source": [ + "from elementary import ElementaryParticle\n", + "\n", + "spin = 1.5\n", + "p = ElementaryParticle(spin)\n", + "p.s\n", + "p.hear_me()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Superclasses\n", + "\n", + "While `ElementaryParticle` is a subclass of `Particle`, it can also be a superclass to other classes, such as `Quark`, which is defined in the next example:" + ] + }, + { + "cell_type": "code", + "execution_count": 108, + "metadata": {}, + "outputs": [], + "source": [ + "import randphys as rp\n", + "\n", + "class Quark(ElementaryParticle):\n", + "\n", + " def __init__(self):\n", + " phys = rp.RandomPhysics()\n", + " self.color = phys.color()\n", + " self.charge = phys.charge()\n", + " self.color_charge = phys.color_charge()\n", + " self.spin = phys.spin()\n", + " self.flavor = phys.flavor()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Decorators and Metaclasses\n", + "\n", + "_MetaProgramming_ is when the definition of a class or a function is specified outside of that function or class. This practice is more common in other languages such as c++ than it is in python. Most of our metaprogramming needs are accomplished with decorators. We can define our own decorators and then add the line `@` above the function definition, as in these examples:" + ] + }, + { + "cell_type": "code", + "execution_count": 110, + "metadata": {}, + "outputs": [], + "source": [ + "def add_is_particle(cls): # Defines the class decorator, which takes one argument that is the class itself.\n", + " cls.is_particle = True # Modifies the class by adding the is_particle attribute.\n", + " return cls # Returns the class\n", + "\n", + "\n", + "@add_is_particle # Applies the decorator to the class. This line uses the same syntax as a function decorator.\n", + "class Particle(object):\n", + " \"\"\"A particle is a constituent unit of the universe.\"\"\"\n", + "\n", + " # ... other parts of the class definition ..." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can even add methods to a class, as follows:" + ] + }, + { + "cell_type": "code", + "execution_count": 111, + "metadata": {}, + "outputs": [], + "source": [ + "from math import sqrt\n", + "\n", + "def add_distance(cls):\n", + " def distance(self, other): \n", + " d2 = 0.0\n", + " for axis in ['x', 'y', 'z']:\n", + " d2 += (self.r[axis] - other.r[axis])**2\n", + " d = sqrt(d2)\n", + " return d\n", + " cls.distance = distance\n", + " return cls \n", + "\n", + "\n", + "@add_distance\n", + "class Particle(object):\n", + " \"\"\"A particle is a constituent unit of the universe.\"\"\"\n", + "\n", + " # ... other parts of the class definition ..." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Metaclasses also exist, for when decorators are not enough. Learn about them from these examples, if you dare:" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "collapsed": false, - "input": [ - "isinstance(Particle, IsParticle)\n", - "p = Particle()" - ], - "language": "python", + "data": { + "text/plain": [ + "type" + ] + }, + "execution_count": 33, "metadata": {}, - "outputs": [], - "prompt_number": 36 - }, + "output_type": "execute_result" + } + ], + "source": [ + "type(type)" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": {}, + "outputs": [], + "source": [ + "class IsParticle(type):\n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": {}, + "outputs": [], + "source": [ + "class Particle(metaclass=IsParticle):\n", + " \"\"\"A particle is a constituent unit of the universe.\"\"\"\n", + "\n", + " # ... other parts of the class definition ..." + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "metadata": {}, + "outputs": [], + "source": [ + "isinstance(Particle, IsParticle)\n", + "p = Particle()" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "collapsed": false, - "input": [ - "isinstance(p, IsParticle)" - ], - "language": "python", + "data": { + "text/plain": [ + "False" + ] + }, + "execution_count": 37, "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 37, - "text": [ - "False" - ] - } - ], - "prompt_number": 37 + "output_type": "execute_result" } ], - "metadata": {} + "source": [ + "isinstance(p, IsParticle)" + ] } - ] -} \ No newline at end of file + ], + "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.6" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/ch08-analysis-and-viz.ipynb b/ch08-analysis-and-viz.ipynb index 6dd5509..7535547 100644 --- a/ch08-analysis-and-viz.ipynb +++ b/ch08-analysis-and-viz.ipynb @@ -1,694 +1,485 @@ { - "metadata": { - "name": "", - "signature": "sha256:1b2eb78fc56f0b97ee6d67edaf1c5c3a8b16d01799de87340d1ace9fe1759d56" - }, - "nbformat": 3, - "nbformat_minor": 0, - "worksheets": [ + "cells": [ { - "cells": [ - { - "cell_type": "code", - "collapsed": false, - "input": [ - "import numpy as np\n", - "decays_arr = np.loadtxt('data/decays.csv', delimiter=\",\", skiprows=1)\n", - "decays_arr" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 1, - "text": [ - "array([[ 0.00000000e+00, 1.00000000e+01],\n", - " [ 1.00000000e+00, 1.35335283e+00],\n", - " [ 2.00000000e+00, 1.83156389e-01],\n", - " [ 3.00000000e+00, 2.47875220e-02],\n", - " [ 4.00000000e+00, 3.35462600e-03],\n", - " [ 5.00000000e+00, 4.53999000e-04],\n", - " [ 6.00000000e+00, 6.14420000e-05],\n", - " [ 7.00000000e+00, 8.31500000e-06],\n", - " [ 8.00000000e+00, 1.12600000e-06],\n", - " [ 9.00000000e+00, 1.52000000e-07]])" - ] - } - ], - "prompt_number": 1 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "import pandas as pd\n", - "decays_df = pd.read_csv('data/decays.csv') \n", - "decays_df" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "html": [ - "
\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
Time (s)Decays (#)
001.000000e+01
111.353353e+00
221.831564e-01
332.478752e-02
443.354626e-03
554.539990e-04
666.144200e-05
778.315000e-06
881.126000e-06
991.520000e-07
\n", - "
" - ], - "metadata": {}, - "output_type": "pyout", - "prompt_number": 2, - "text": [ - " Time (s) Decays (#)\n", - "0 0 1.000000e+01\n", - "1 1 1.353353e+00\n", - "2 2 1.831564e-01\n", - "3 3 2.478752e-02\n", - "4 4 3.354626e-03\n", - "5 5 4.539990e-04\n", - "6 6 6.144200e-05\n", - "7 7 8.315000e-06\n", - "8 8 1.126000e-06\n", - "9 9 1.520000e-07" - ] - } - ], - "prompt_number": 2 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "# can convert to HDF5 format\n", - "#decays_df.to_hdf('decays.h5', 'experimental')" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 3 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "import blaze as bz\n", - "csv_data = bz.CSV('data/decays.csv')\n", - "decays_tb = bz.Table(csv_data)" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 4 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "decay_df = pd.read_csv(\"data/many_decays.csv\")\n", - "decay_df.count()" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 5, - "text": [ - "Time 50\n", - "Decays 46\n", - "dtype: int64" - ] - } - ], - "prompt_number": 5 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "decay_df.dropna()" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "html": [ - "
\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
TimeDecays
02014-11-08T05:19:31.5617821.000000e+01
12014-11-08T05:19:32.5617821.353353e+00
22014-11-08T05:19:33.5617821.831564e-01
32014-11-08T05:19:34.5617822.478752e-02
42014-11-08T05:19:35.5617823.354626e-03
52014-11-08T05:19:36.5617824.539993e-04
62014-11-08T05:19:37.5617826.144212e-05
72014-11-08T05:19:38.5617828.315287e-06
82014-11-08T05:19:39.5617821.125352e-06
92014-11-08T05:19:40.5617821.522998e-07
102014-11-08T05:19:41.5617822.061154e-08
112014-11-08T05:19:42.5617822.789468e-09
122014-11-08T05:19:43.5617823.775135e-10
132014-11-08T05:19:44.5617825.109089e-11
142014-11-08T05:19:45.5617826.914400e-12
152014-11-08T05:19:46.5617829.357623e-13
162014-11-08T05:19:47.5617822.000000e+00
172014-11-08T05:19:48.5617822.000000e+00
182014-11-08T05:19:49.5617822.000000e+00
192014-11-08T05:19:50.5617822.000000e+00
202014-11-08T05:19:51.5617822.000000e+00
212014-11-08T05:19:52.5617822.000000e+00
222014-11-08T05:19:53.5617822.000000e+00
232014-11-08T05:19:54.5617822.000000e+00
242014-11-08T05:19:55.5617822.000000e+00
252014-11-08T05:19:56.5617821.928750e-21
262014-11-08T05:19:57.5617822.610279e-22
272014-11-08T05:19:58.5617823.532629e-23
282014-11-08T05:19:59.5617824.780893e-24
292014-11-08T05:20:00.5617826.470235e-25
302014-11-08T05:20:01.5617828.756511e-26
312014-11-08T05:20:02.5617821.185065e-26
322014-11-08T05:20:03.5617821.603811e-27
332014-11-08T05:20:04.5617822.170522e-28
342014-11-08T05:20:05.5617822.937482e-29
352014-11-08T05:20:06.5617823.975450e-30
362014-11-08T05:20:07.5617825.380186e-31
372014-11-08T05:20:08.5617827.281290e-32
382014-11-08T05:20:09.5617829.854155e-33
392014-11-08T05:20:10.5617821.333615e-33
402014-11-08T05:20:11.5617821.804851e-34
452014-11-08T05:20:16.5617828.194013e-39
462014-11-08T05:20:17.5617821.108939e-39
472014-11-08T05:20:18.5617821.500786e-40
482014-11-08T05:20:19.5617822.031093e-41
492014-11-08T05:20:20.5617822.748785e-42
\n", - "
" - ], - "metadata": {}, - "output_type": "pyout", - "prompt_number": 6, - "text": [ - " Time Decays\n", - "0 2014-11-08T05:19:31.561782 1.000000e+01\n", - "1 2014-11-08T05:19:32.561782 1.353353e+00\n", - "2 2014-11-08T05:19:33.561782 1.831564e-01\n", - "3 2014-11-08T05:19:34.561782 2.478752e-02\n", - "4 2014-11-08T05:19:35.561782 3.354626e-03\n", - "5 2014-11-08T05:19:36.561782 4.539993e-04\n", - "6 2014-11-08T05:19:37.561782 6.144212e-05\n", - "7 2014-11-08T05:19:38.561782 8.315287e-06\n", - "8 2014-11-08T05:19:39.561782 1.125352e-06\n", - "9 2014-11-08T05:19:40.561782 1.522998e-07\n", - "10 2014-11-08T05:19:41.561782 2.061154e-08\n", - "11 2014-11-08T05:19:42.561782 2.789468e-09\n", - "12 2014-11-08T05:19:43.561782 3.775135e-10\n", - "13 2014-11-08T05:19:44.561782 5.109089e-11\n", - "14 2014-11-08T05:19:45.561782 6.914400e-12\n", - "15 2014-11-08T05:19:46.561782 9.357623e-13\n", - "16 2014-11-08T05:19:47.561782 2.000000e+00\n", - "17 2014-11-08T05:19:48.561782 2.000000e+00\n", - "18 2014-11-08T05:19:49.561782 2.000000e+00\n", - "19 2014-11-08T05:19:50.561782 2.000000e+00\n", - "20 2014-11-08T05:19:51.561782 2.000000e+00\n", - "21 2014-11-08T05:19:52.561782 2.000000e+00\n", - "22 2014-11-08T05:19:53.561782 2.000000e+00\n", - "23 2014-11-08T05:19:54.561782 2.000000e+00\n", - "24 2014-11-08T05:19:55.561782 2.000000e+00\n", - "25 2014-11-08T05:19:56.561782 1.928750e-21\n", - "26 2014-11-08T05:19:57.561782 2.610279e-22\n", - "27 2014-11-08T05:19:58.561782 3.532629e-23\n", - "28 2014-11-08T05:19:59.561782 4.780893e-24\n", - "29 2014-11-08T05:20:00.561782 6.470235e-25\n", - "30 2014-11-08T05:20:01.561782 8.756511e-26\n", - "31 2014-11-08T05:20:02.561782 1.185065e-26\n", - "32 2014-11-08T05:20:03.561782 1.603811e-27\n", - "33 2014-11-08T05:20:04.561782 2.170522e-28\n", - "34 2014-11-08T05:20:05.561782 2.937482e-29\n", - "35 2014-11-08T05:20:06.561782 3.975450e-30\n", - "36 2014-11-08T05:20:07.561782 5.380186e-31\n", - "37 2014-11-08T05:20:08.561782 7.281290e-32\n", - "38 2014-11-08T05:20:09.561782 9.854155e-33\n", - "39 2014-11-08T05:20:10.561782 1.333615e-33\n", - "40 2014-11-08T05:20:11.561782 1.804851e-34\n", - "45 2014-11-08T05:20:16.561782 8.194013e-39\n", - "46 2014-11-08T05:20:17.561782 1.108939e-39\n", - "47 2014-11-08T05:20:18.561782 1.500786e-40\n", - "48 2014-11-08T05:20:19.561782 2.031093e-41\n", - "49 2014-11-08T05:20:20.561782 2.748785e-42" - ] - } - ], - "prompt_number": 6 - }, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Analysis and Visualization\n", + "\n", + "Data analysis and visualization are essential to science. This chapter will teach you the best ways to perform data analysis and visualization on the computer, saving time and allowing for more publications.\n", + "\n", + "Scientists encounter many types of data. Once those data have been collected and prepared, they must be loaded into the computer." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Loading Data\n", + "\n", + "There are numerous python packages for loading data into memory-accesible structures. These will be discussed in detail in chapter 11. Here, we will focus on four tools: NumPy, PyTables, Pandas, and Blaze. \n", + "\n", + "Numerous factors determine the right tool for data analysis. The most important factor is often the size of the data. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### NumPy\n", + "\n", + "For small data that can be loaded into memory all at once, NumPy is often a good choice. We will begin our discussion there. NumPy arranges data into an array of numbers. NumPy arrays are very common and very powerful. \n", + "\n", + "Below is code that tabulates the results of a count of a decaying isotope. The left-hand column holds the independent variable, time, and the right hand column holds the dependent variable, the observed number of decays. The data are loaded by NumPy from a comma separated value file with the following code: " + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "collapsed": false, - "input": [ - "import numpy as np\n", - "\n", - "# as in the previous example, load decays.csv into a NumPy array\n", - "decaydata = np.loadtxt('data/decays.csv', delimiter=\",\", skiprows=1)\n", - "\n", - "# provide handles for the x and y columns\n", - "time = decaydata[:,0]\n", - "decays = decaydata[:,1]\n", - "\n", - "# import the matplotlib plotting functionality\n", - "import matplotlib\n", - "%matplotlib inline\n", - "import pylab as plt\n", - "\n", - "plt.plot(time, decays)\n", - "\n", - "plt.xlabel('Time (s)')\n", - "plt.ylabel('Decays')\n", - "plt.title('Decays')\n", - "plt.grid(True)\n", - "#plt.savefig(\"decays_matplotlib.png\")" - ], - "language": "python", + "data": { + "text/plain": [ + "array([[0.00000000e+00, 1.00000000e+01],\n", + " [1.00000000e+00, 1.35335283e+00],\n", + " [2.00000000e+00, 1.83156389e-01],\n", + " [3.00000000e+00, 2.47875220e-02],\n", + " [4.00000000e+00, 3.35462600e-03],\n", + " [5.00000000e+00, 4.53999000e-04],\n", + " [6.00000000e+00, 6.14420000e-05],\n", + " [7.00000000e+00, 8.31500000e-06],\n", + " [8.00000000e+00, 1.12600000e-06],\n", + " [9.00000000e+00, 1.52000000e-07]])" + ] + }, + "execution_count": 25, "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "display_data", - "png": "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\n", - "text": [ - "" - ] - } - ], - "prompt_number": 7 - }, + "output_type": "execute_result" + } + ], + "source": [ + "import numpy as np # Imports numpy with alias np\n", + "decays_arr = np.loadtxt('data/decays.csv', delimiter=\",\", skiprows=1) # Creates an object with the loadtxt() function\n", + "decays_arr" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Pandas\n", + "\n", + "Pandas is a very flexible tool that provides a good alternative to NumPy or PyTables in many cases. \n", + "\n", + "It is very easy to load data into pandas. Observe:" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "collapsed": false, - "input": [ - "# Import various necessary Python and matplotlib packages\n", - "import numpy as np\n", - "import matplotlib.cm as cm\n", - "from matplotlib.pyplot import figure, show, rc\n", - "from matplotlib.patches import Ellipse\n", - "\n", - "# Create a square figure on which to place the plot\n", - "fig = figure(figsize=(8,8))\n", - "\n", - "# Create square axes to hold the circular polar plot\n", - "ax = fig.add_axes([0.1, 0.1, 0.8, 0.8], polar=True)\n", - "\n", - "# Generate 20 colored, angular wedges for the polar plot\n", - "N = 20\n", - "theta = np.arange(0.0, 2*np.pi, 2*np.pi/N)\n", - "radii = 10*np.random.rand(N)\n", - "width = np.pi/4*np.random.rand(N)\n", - "bars = ax.bar(theta, radii, width=width, bottom=0.0)\n", - "for r,bar in zip(radii, bars):\n", - " bar.set_facecolor(cm.jet(r/10.))\n", - " bar.set_alpha(0.5)\n", - "\n", - "# Using dictionaries, create a color scheme for the text boxes\n", - "bbox_args = dict(boxstyle=\"round, pad=0.9\", fc=\"green\", alpha=0.5)\n", - "bbox_white = dict(boxstyle=\"round, pad=0.9\", fc=\"1\", alpha=0.9)\n", - "patch_white = dict(boxstyle=\"round, pad=1\", fc=\"1\", ec=\"1\")\n", - "\n", - "# Create various boxes with text annotations in them at specific\n", - "# x and y coordinates\n", - "ax.annotate(\" \",\n", - " xy=(.5,.93),\n", - " xycoords='figure fraction',\n", - " ha=\"center\", va=\"center\",\n", - " bbox=patch_white)\n", - "\n", - "ax.annotate('Matplotlib and the Python Ecosystem for Scientific Computing',\n", - " xy=(.5,.95),\n", - " xycoords='figure fraction',\n", - " xytext=(0, 0), textcoords='offset points',\n", - " size=15,\n", - " ha=\"center\", va=\"center\",\n", - " bbox=bbox_args)\n", - "\n", - "ax.annotate('Author and Lead Developer \\n of Matplotlib ',\n", - " xy=(.5,.82),\n", - " xycoords='figure fraction',\n", - " xytext=(0, 0), textcoords='offset points',\n", - " ha=\"center\", va=\"center\",\n", - " bbox=bbox_args)\n", - "\n", - "ax.annotate('John D. Hunter',\n", - " xy=(.5,.89),\n", - " xycoords='figure fraction',\n", - " xytext=(0, 0), textcoords='offset points',\n", - " size=15,\n", - " ha=\"center\", va=\"center\",\n", - " bbox=bbox_white)\n", - "\n", - "ax.annotate('Friday November 5th \\n 2:00 pm \\n1106ME ',\n", - " xy=(.5,.25),\n", - " xycoords='figure fraction',\n", - " xytext=(0, 0), textcoords='offset points',\n", - " size=15,\n", - " ha=\"center\", va=\"center\",\n", - " bbox=bbox_args)\n", - "\n", - "ax.annotate('Sponsored by: \\n The Hacker Within, \\n'\n", - " 'The University Lectures Committee, \\n The Department of '\n", - " 'Medical Physics\\n and \\n The American Nuclear Society',\n", - " xy=(.78,.1),\n", - " xycoords='figure fraction',\n", - " xytext=(0, 0), textcoords='offset points',\n", - " size=9,\n", - " ha=\"center\", va=\"center\",\n", - " bbox=bbox_args)\n", - "\n", - "#fig.savefig(\"plot.pdf\")" - ], - "language": "python", + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Time (s)Decays (#)
001.000000e+01
111.353353e+00
221.831564e-01
332.478752e-02
443.354626e-03
554.539990e-04
666.144200e-05
778.315000e-06
881.126000e-06
991.520000e-07
\n", + "
" + ], + "text/plain": [ + " Time (s) Decays (#)\n", + "0 0 1.000000e+01\n", + "1 1 1.353353e+00\n", + "2 2 1.831564e-01\n", + "3 3 2.478752e-02\n", + "4 4 3.354626e-03\n", + "5 5 4.539990e-04\n", + "6 6 6.144200e-05\n", + "7 7 8.315000e-06\n", + "8 8 1.126000e-06\n", + "9 9 1.520000e-07" + ] + }, + "execution_count": 26, "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 8, - "text": [ - "" - ] - }, - { - "metadata": {}, - "output_type": "display_data", - "png": "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\n", - "text": [ - "" - ] - } - ], - "prompt_number": 8 - }, + "output_type": "execute_result" + } + ], + "source": [ + "import pandas as pd # Import pandas in alias it as pd\n", + "decays_df = pd.read_csv('data/decays.csv') # Creates a data frame object to hold the data loaded by read_csv()\n", + "decays_df" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can also use pandas to change the format of data. This code will create to an hdf5 file called _decays.h5_ in a group node called _experimental_ if we ran it:" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": {}, + "outputs": [], + "source": [ + "# import pandas as pd\n", + "# decays_df = pd.read_csv('data/decays.csv')\n", + "\n", + "# decays_df.to_hdf('decays.h5', 'experimental')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Blaze \n", + "\n", + "Blaze is another tool. Similar to Panda, it can easily convert data between different formats. However, blaze is still in active development, and not fully stable. Please be cautious if you decide to use blaze. The following code takes the CSV code and turns it into a data descriptor, which it then transforms ito Blaze Table" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": { + "scrolled": true + }, + "outputs": [ { - "cell_type": "code", - "collapsed": false, - "input": [ - "import numpy as np\n", - "# import the Bokeh plotting tools\n", - "from bokeh import plotting as bp\n", - "\n", - "# as in the matplotlib example, load decays.csv into a NumPy array\n", - "decaydata = np.loadtxt('data/decays.csv',delimiter=\",\",skiprows=1)\n", - "\n", - "# provide handles for the x and y columns\n", - "time = decaydata[:,0]\n", - "decays = decaydata[:,1]\n", - "\n", - "# define some output file metadata\n", - "bp.output_file(\"decays.html\", title=\"Experiment 1 Radioactivity\")\n", - "\n", - "# create a figure with fun Internet-friendly features (optional)\n", - "bp.figure(tools=\"pan,wheel_zoom,box_zoom,reset,previewsave\")\n", - "\n", - "# on that figure, create a line plot\n", - "bp.line(time, decays, x_axis_label=\"Time (s)\", y_axis_label=\"Decays (#)\",\n", - " color='#1F78B4', legend='Decays per second')\n", - "\n", - "# additional customization to the figure can be specified separately\n", - "bp.curplot().title = \"Decays\"\n", - "bp.grid().grid_line_alpha=0.3\n", - "\n", - "# open a browser\n", - "bp.show()" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "ename": "AttributeError", - "evalue": "'module' object has no attribute 'line'", - "output_type": "pyerr", - "traceback": [ - "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[1;31mAttributeError\u001b[0m Traceback (most recent call last)", - "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[0;32m 17\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 18\u001b[0m \u001b[1;31m# on that figure, create a line plot\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 19\u001b[1;33m bp.line(time, decays, x_axis_label=\"Time (s)\", y_axis_label=\"Decays (#)\",\n\u001b[0m\u001b[0;32m 20\u001b[0m color='#1F78B4', legend='Decays per second')\n\u001b[0;32m 21\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n", - "\u001b[1;31mAttributeError\u001b[0m: 'module' object has no attribute 'line'" - ] - } - ], - "prompt_number": 9 + "ename": "AttributeError", + "evalue": "module 'pandas.core.computation' has no attribute 'expressions'", + "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[0;32mimport\u001b[0m \u001b[0mblaze\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0mbz\u001b[0m \u001b[0;31m# Imports blaze and aliases as bz\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 2\u001b[0m \u001b[0mcsv_data\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mbz\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mCSV\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'data/decays.csv'\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;31m# Uses the CSV() constructor to transform the csv into blaze data\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0mdecays_tb\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mbz\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mTable\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mcsv_data\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;31m# Transforms the data descripter csv_data into a blaze table\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/anaconda3/lib/python3.5/site-packages/blaze/__init__.py\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 7\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 8\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0mpandas\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mDataFrame\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 9\u001b[0;31m \u001b[0;32mfrom\u001b[0m \u001b[0modo\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0modo\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mconvert\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mappend\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdrop\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mresource\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 10\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0modo\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mbackends\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcsv\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mCSV\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 11\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0modo\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mbackends\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mjson\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mJSON\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mJSONLines\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/anaconda3/lib/python3.5/site-packages/odo/__init__.py\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 63\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0;34m.\u001b[0m\u001b[0mbackends\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0murl\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mURL\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 64\u001b[0m \u001b[0;32mwith\u001b[0m \u001b[0mignoring\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mImportError\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 65\u001b[0;31m \u001b[0;32mfrom\u001b[0m \u001b[0;34m.\u001b[0m\u001b[0mbackends\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdask\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mdask\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 66\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 67\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/anaconda3/lib/python3.5/site-packages/odo/backends/dask.py\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 11\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mdask\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mbag\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0mdb\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 12\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0mdask\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcompatibility\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mlong\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 13\u001b[0;31m \u001b[0;32mimport\u001b[0m \u001b[0mdask\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdataframe\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0mdd\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 14\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 15\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0modo\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mappend\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mchunks\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mconvert\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdiscover\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mTextFile\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/anaconda3/lib/python3.5/site-packages/dask/dataframe/__init__.py\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0m__future__\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mprint_function\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdivision\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mabsolute_import\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 3\u001b[0;31m from .core import (DataFrame, Series, Index, _Frame, map_partitions,\n\u001b[0m\u001b[1;32m 4\u001b[0m repartition, to_delayed, to_datetime)\n\u001b[1;32m 5\u001b[0m from .io import (from_array, from_pandas, from_bcolz,\n", + "\u001b[0;32m~/anaconda3/lib/python3.5/site-packages/dask/dataframe/core.py\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 38\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mPANDAS_VERSION\u001b[0m \u001b[0;34m>=\u001b[0m \u001b[0;34m'0.20.0'\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 39\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0mpandas\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mutil\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mcache_readonly\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 40\u001b[0;31m \u001b[0mpd\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcore\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcomputation\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mexpressions\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mset_use_numexpr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;32mFalse\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 41\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 42\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0mpandas\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mutil\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdecorators\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mcache_readonly\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mAttributeError\u001b[0m: module 'pandas.core.computation' has no attribute 'expressions'" + ] } ], - "metadata": {} + "source": [ + "import blaze as bz # Imports blaze and aliases as bz\n", + "csv_data = bz.CSV('data/decays.csv') # Uses the CSV() constructor to transform the csv into blaze data\n", + "decays_tb = bz.Table(csv_data) # Transforms the data descripter csv_data into a blaze table" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Cleaning and Munging Data\n", + "\n", + "Data munging refers to many things, but broadly means dealing with data. Typically, munging means converting data from its raw form to a well-structued format that can be used for plotting. \n", + "\n", + "Suppose you performed an experiment counting the decay rate of a radioative source. However, a few things went wrong with the experiment and you cannot repeat the experiment due to time or financial constraints. In particular, let's imagine that during the measurement, a colleague walked through the laboratory with a stronger, more stable source so that many of the measurements are biased by this strong source. Additionally, the lab lost power for a few seconds towards the end of the measurement, so some measurements are nonexistant. \n", + "\n", + "First let's use Panda to remove the rows from our table with missing data:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "decay_df = pd.read_csv(\"data/many_decays.csv\")\n", + "decay_df.count() # The count() method ignores the NaN values" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "decay_df.dropna() # The dropna() method returns the dataframe without the NaN values" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Visualisation \n", + "\n", + "Now that the data are a bit cleaner, let's plot them.\n", + "\n", + "#### MatPlotLib\n", + "\n", + "Matplotlib is an amazing plotting tool for scientific computing. The following python script will create a plot of the decay data:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np # Imports and aliases NumPy\n", + "\n", + "# as in the previous example, load decays.csv into a NumPy array\n", + "decaydata = np.loadtxt('data/decays.csv', delimiter=\",\", skiprows=1)\n", + "\n", + "# provide handles for the x and y columns\n", + "time = decaydata[:,0]\n", + "decays = decaydata[:,1]\n", + "\n", + "# import the matplotlib plotting functionality\n", + "import matplotlib\n", + "%matplotlib inline\n", + "import pylab as plt\n", + "\n", + "plt.plot(time, decays) # Generates a plot of decays vs time\n", + "\n", + "plt.xlabel('Time (s)')\n", + "plt.ylabel('Decays')\n", + "plt.title('Decays')\n", + "plt.grid(True) # Adds gridlines\n", + "#plt.savefig(\"decays_matplotlib.png\") # saves the figure as a png" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Here is an example of a rather long script to make a nice flyer for a talk about MatPlotLib:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Import various necessary Python and matplotlib packages\n", + "import numpy as np\n", + "import matplotlib.cm as cm # Imports the colormaps library\n", + "from matplotlib.pyplot import figure, show, rc # Imports other useful libraries\n", + "from matplotlib.patches import Ellipse # We need the ellipse shape for our text boxes\n", + "\n", + "# Create a square figure on which to place the plot\n", + "fig = figure(figsize=(8,8))\n", + "\n", + "# Create square axes to hold the circular polar plot\n", + "ax = fig.add_axes([0.1, 0.1, 0.8, 0.8], polar=True)\n", + "\n", + "# Generate 20 colored, angular wedges for the polar plot\n", + "N = 20\n", + "theta = np.arange(0.0, 2*np.pi, 2*np.pi/N)\n", + "radii = 10*np.random.rand(N)\n", + "width = np.pi/4*np.random.rand(N)\n", + "bars = ax.bar(theta, radii, width=width, bottom=0.0)\n", + "for r,bar in zip(radii, bars):\n", + " bar.set_facecolor(cm.jet(r/10.))\n", + " bar.set_alpha(0.5)\n", + "\n", + "# Using dictionaries, create a color scheme for the text boxes\n", + "bbox_args = dict(boxstyle=\"round, pad=0.9\", fc=\"green\", alpha=0.5)\n", + "bbox_white = dict(boxstyle=\"round, pad=0.9\", fc=\"1\", alpha=0.9)\n", + "patch_white = dict(boxstyle=\"round, pad=1\", fc=\"1\", ec=\"1\")\n", + "\n", + "# Create various boxes with text annotations in them at specific\n", + "# x and y coordinates\n", + "ax.annotate(\" \",\n", + " xy=(.5,.93), # Places an annotation box at the desired x amd y coordinates \n", + " xycoords='figure fraction', # Tells python to read those annotations as fractions of figure height and width\n", + " ha=\"center\", va=\"center\", # Aligns the text to the center of the box\n", + " bbox=patch_white) # Makes the box white\n", + "\n", + "ax.annotate('Matplotlib and the Python Ecosystem for Scientific Computing',\n", + " xy=(.5,.95),\n", + " xycoords='figure fraction',\n", + " xytext=(0, 0), textcoords='offset points',\n", + " size=15,\n", + " ha=\"center\", va=\"center\",\n", + " bbox=bbox_args)\n", + "\n", + "ax.annotate('Author and Lead Developer \\n of Matplotlib ',\n", + " xy=(.5,.82),\n", + " xycoords='figure fraction',\n", + " xytext=(0, 0), textcoords='offset points',\n", + " ha=\"center\", va=\"center\",\n", + " bbox=bbox_args)\n", + "\n", + "ax.annotate('John D. Hunter',\n", + " xy=(.5,.89),\n", + " xycoords='figure fraction',\n", + " xytext=(0, 0), textcoords='offset points',\n", + " size=15,\n", + " ha=\"center\", va=\"center\",\n", + " bbox=bbox_white)\n", + "\n", + "ax.annotate('Friday November 5th \\n 2:00 pm \\n1106ME ',\n", + " xy=(.5,.25),\n", + " xycoords='figure fraction',\n", + " xytext=(0, 0), textcoords='offset points',\n", + " size=15,\n", + " ha=\"center\", va=\"center\",\n", + " bbox=bbox_args)\n", + "\n", + "ax.annotate('Sponsored by: \\n The Hacker Within, \\n'\n", + " 'The University Lectures Committee, \\n The Department of '\n", + " 'Medical Physics\\n and \\n The American Nuclear Society',\n", + " xy=(.78,.1),\n", + " xycoords='figure fraction',\n", + " xytext=(0, 0), textcoords='offset points',\n", + " size=9,\n", + " ha=\"center\", va=\"center\",\n", + " bbox=bbox_args)\n", + "\n", + "#fig.savefig(\"plot.pdf\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Further cool examples of plots made with MatPlotLib may be found at the MatPlotLib gallery" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Bokeh\n", + "\n", + "Bokeh is another plotting tool that is quite similar to MatPlotLib, but specialized for generating interactive plots for the internet. The following script makes an html file holding the plot of the decay data:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "# import the Bokeh plotting tools\n", + "from bokeh import plotting as bp\n", + "\n", + "# as in the matplotlib example, load decays.csv into a NumPy array\n", + "decaydata = np.loadtxt('data/decays.csv',delimiter=\",\",skiprows=1)\n", + "\n", + "# provide handles for the x and y columns\n", + "time = decaydata[:,0]\n", + "decays = decaydata[:,1]\n", + "\n", + "# define some output file metadata\n", + "bp.output_file(\"decays.html\", title=\"Experiment 1 Radioactivity\")\n", + "\n", + "# create a figure with fun Internet-friendly features (optional)\n", + "bp.figure(tools=\"pan,wheel_zoom,box_zoom,reset,previewsave\")\n", + "\n", + "# on that figure, create a line plot\n", + "bp.figure().line(time, decays, x_axis_label=\"Time (s)\", y_axis_label=\"Decays (#)\",\n", + " color='#1F78B4', legend='Decays per second')\n", + "\n", + "# additional customization to the figure can be specified separately\n", + "bp.curplot().title = \"Decays\"\n", + "bp.grid().grid_line_alpha=0.3\n", + "\n", + "# open a browser\n", + "bp.show()" + ] } - ] -} \ No newline at end of file + ], + "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.6" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +}