Skip to content

Instantly share code, notes, and snippets.

@damontallen
Created July 4, 2013 18:16
Show Gist options
  • Save damontallen/5929466 to your computer and use it in GitHub Desktop.
Save damontallen/5929466 to your computer and use it in GitHub Desktop.
A Crash Course in Python for Scientists (in four parts)
Display the source blob
Display the rendered blob
Raw
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
{
"metadata": {
"name": "Crash Course v0.5c"
},
"nbformat": 3,
"nbformat_minor": 0,
"worksheets": [
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# III. Intermediate Python\n",
"\n",
"## Output Parsing\n",
"As more and more of our day-to-day work is being done on and through computers, we increasingly have output that one program writes, often in a text file, that we need to analyze in one way or another, and potentially feed that output into another file.\n",
"\n",
"Suppose we have the following output:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"myoutput = \"\"\"\\\n",
"@ Step Energy Delta E Gmax Grms Xrms Xmax Walltime\n",
"@ ---- ---------------- -------- -------- -------- -------- -------- --------\n",
"@ 0 -6095.12544083 0.0D+00 0.03686 0.00936 0.00000 0.00000 1391.5\n",
"@ 1 -6095.25762870 -1.3D-01 0.00732 0.00168 0.32456 0.84140 10468.0\n",
"@ 2 -6095.26325979 -5.6D-03 0.00233 0.00056 0.06294 0.14009 11963.5\n",
"@ 3 -6095.26428124 -1.0D-03 0.00109 0.00024 0.03245 0.10269 13331.9\n",
"@ 4 -6095.26463203 -3.5D-04 0.00057 0.00013 0.02737 0.09112 14710.8\n",
"@ 5 -6095.26477615 -1.4D-04 0.00043 0.00009 0.02259 0.08615 20211.1\n",
"@ 6 -6095.26482624 -5.0D-05 0.00015 0.00002 0.00831 0.03147 21726.1\n",
"@ 7 -6095.26483584 -9.6D-06 0.00021 0.00004 0.01473 0.05265 24890.5\n",
"@ 8 -6095.26484405 -8.2D-06 0.00005 0.00001 0.00555 0.01929 26448.7\n",
"@ 9 -6095.26484599 -1.9D-06 0.00003 0.00001 0.00164 0.00564 27258.1\n",
"@ 10 -6095.26484676 -7.7D-07 0.00003 0.00001 0.00161 0.00553 28155.3\n",
"@ 11 -6095.26484693 -1.8D-07 0.00002 0.00000 0.00054 0.00151 28981.7\n",
"@ 11 -6095.26484693 -1.8D-07 0.00002 0.00000 0.00054 0.00151 28981.7\"\"\""
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 138
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This output actually came from a geometry optimization of a Silicon cluster using the [NWChem](http://www.nwchem-sw.org/index.php/Main_Page) quantum chemistry suite. At every step the program computes the energy of the molecular geometry, and then changes the geometry to minimize the computed forces, until the energy converges. I obtained this output via the unix command\n",
"\n",
" % grep @ nwchem.out\n",
"\n",
"since NWChem is nice enough to precede the lines that you need to monitor job progress with the '@' symbol.\n",
"\n",
"We could do the entire analysis in Python; I'll show how to do this later on, but first let's focus on turning this code into a usable Python object that we can plot.\n",
"\n",
"First, note that the data is entered into a multi-line string. When Python sees three quote marks \"\"\" or ''' it treats everything following as part of a single string, including newlines, tabs, and anything else, until it sees the same three quote marks (\"\"\" has to be followed by another \"\"\", and ''' has to be followed by another ''') again. This is a convenient way to quickly dump data into Python, and it also reinforces the important idea that you don't have to open a file and deal with it one line at a time. You can read everything in, and deal with it as one big chunk.\n",
"\n",
"The first thing we'll do, though, is to split the big string into a list of strings, since each line corresponds to a separate piece of data. We will use the **splitlines()** function on the big myout string to break it into a new element every time it sees a newline (\\n) character:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"lines = myoutput.splitlines()\n",
"lines"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 139,
"text": [
"['@ Step Energy Delta E Gmax Grms Xrms Xmax Walltime',\n",
" '@ ---- ---------------- -------- -------- -------- -------- -------- --------',\n",
" '@ 0 -6095.12544083 0.0D+00 0.03686 0.00936 0.00000 0.00000 1391.5',\n",
" '@ 1 -6095.25762870 -1.3D-01 0.00732 0.00168 0.32456 0.84140 10468.0',\n",
" '@ 2 -6095.26325979 -5.6D-03 0.00233 0.00056 0.06294 0.14009 11963.5',\n",
" '@ 3 -6095.26428124 -1.0D-03 0.00109 0.00024 0.03245 0.10269 13331.9',\n",
" '@ 4 -6095.26463203 -3.5D-04 0.00057 0.00013 0.02737 0.09112 14710.8',\n",
" '@ 5 -6095.26477615 -1.4D-04 0.00043 0.00009 0.02259 0.08615 20211.1',\n",
" '@ 6 -6095.26482624 -5.0D-05 0.00015 0.00002 0.00831 0.03147 21726.1',\n",
" '@ 7 -6095.26483584 -9.6D-06 0.00021 0.00004 0.01473 0.05265 24890.5',\n",
" '@ 8 -6095.26484405 -8.2D-06 0.00005 0.00001 0.00555 0.01929 26448.7',\n",
" '@ 9 -6095.26484599 -1.9D-06 0.00003 0.00001 0.00164 0.00564 27258.1',\n",
" '@ 10 -6095.26484676 -7.7D-07 0.00003 0.00001 0.00161 0.00553 28155.3',\n",
" '@ 11 -6095.26484693 -1.8D-07 0.00002 0.00000 0.00054 0.00151 28981.7',\n",
" '@ 11 -6095.26484693 -1.8D-07 0.00002 0.00000 0.00054 0.00151 28981.7']"
]
}
],
"prompt_number": 139
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Splitting is a big concept in text processing. We used **splitlines()** here, and we will use the more general **split()** function below to split each line into whitespace-delimited words.\n",
"\n",
"We now want to do three things:\n",
"\n",
"* Skip over the lines that don't carry any information\n",
"* Break apart each line that does carry information and grab the pieces we want\n",
"* Turn the resulting data into something that we can plot.\n",
"\n",
"For this data, we really only want the Energy column, the Gmax column (which contains the maximum gradient at each step), and perhaps the Walltime column. \n",
"\n",
"Since the data is now in a list of lines, we can iterate over it:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"for line in lines[2:]:\n",
" # do something with each line\n",
" words = line.split()"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 140
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Let's examine what we just did: first, we used a **for** loop to iterate over each line. However, we skipped the first two (the lines[2:] only takes the lines starting from index 2), since lines[0] contained the title information, and lines[1] contained underscores.\n",
"\n",
"We then split each line into chunks (which we're calling \"words\", even though in most cases they're numbers) using the string **split()** command. Here's what split does:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"#import string\n",
"help(\"\".split)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"Help on built-in function split:\n",
"\n",
"split(...)\n",
" S.split([sep[, maxsplit]]) -> 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"
]
}
],
"prompt_number": 141
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Here we're implicitly passing in the first argument (s, in the doctext) by calling a method .split() on a string object. In this instance, we're not passing in a sep character, which means that the function splits on whitespace. Let's see what that does to one of our lines:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"lines[2].split()"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 142,
"text": [
"['@',\n",
" '0',\n",
" '-6095.12544083',\n",
" '0.0D+00',\n",
" '0.03686',\n",
" '0.00936',\n",
" '0.00000',\n",
" '0.00000',\n",
" '1391.5']"
]
}
],
"prompt_number": 142
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This is almost exactly what we want. We just have to now pick the fields we want:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"for line in lines[2:]:\n",
" # do something with each line\n",
" words = line.split()\n",
" energy = words[2]\n",
" gmax = words[4]\n",
" time = words[8]\n",
" print(energy,gmax,time)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"-6095.12544083 0.03686 1391.5\n",
"-6095.25762870 0.00732 10468.0\n",
"-6095.26325979 0.00233 11963.5\n",
"-6095.26428124 0.00109 13331.9\n",
"-6095.26463203 0.00057 14710.8\n",
"-6095.26477615 0.00043 20211.1\n",
"-6095.26482624 0.00015 21726.1\n",
"-6095.26483584 0.00021 24890.5\n",
"-6095.26484405 0.00005 26448.7\n",
"-6095.26484599 0.00003 27258.1\n",
"-6095.26484676 0.00003 28155.3\n",
"-6095.26484693 0.00002 28981.7\n",
"-6095.26484693 0.00002 28981.7\n"
]
}
],
"prompt_number": 143
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This is fine for printing things out, but if we want to do something with the data, either make a calculation with it or pass it into a plotting, we need to convert the strings into regular floating point numbers. We can use the **float()** command for this. We also need to save it in some form. I'll do this as follows:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"data = []\n",
"for line in lines[2:]:\n",
" # do something with each line\n",
" words = line.split()\n",
" energy = float(words[2])\n",
" gmax = float(words[4])\n",
" time = float(words[8])\n",
" data.append((energy,gmax,time))\n",
"data = array(data)"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 144
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We now have our data in a numpy array, so we can choose columns to print:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"plot(data[:,0])\n",
"xlabel('step')\n",
"ylabel('Energy (hartrees)')\n",
"title('Convergence of NWChem geometry optimization for Si cluster')"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 145,
"text": [
"<matplotlib.text.Text at 0x7689550>"
]
},
{
"output_type": "display_data",
"png": "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\n"
}
],
"prompt_number": 145
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"I would write the code a little more succinctly if I were doing this for myself, but this is essentially a snippet I use repeatedly. \n",
"\n",
"Suppose our data was in CSV (comma separated values) format, a format that originally came from Microsoft Excel, and is increasingly used as a data interchange format in big data applications. How would we parse that?"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"csv = \"\"\"\\\n",
"-6095.12544083, 0.03686, 1391.5\n",
"-6095.25762870, 0.00732, 10468.0\n",
"-6095.26325979, 0.00233, 11963.5\n",
"-6095.26428124, 0.00109, 13331.9\n",
"-6095.26463203, 0.00057, 14710.8\n",
"-6095.26477615, 0.00043, 20211.1\n",
"-6095.26482624, 0.00015, 21726.1\n",
"-6095.26483584, 0.00021, 24890.5\n",
"-6095.26484405, 0.00005, 26448.7\n",
"-6095.26484599, 0.00003, 27258.1\n",
"-6095.26484676, 0.00003, 28155.3\n",
"-6095.26484693, 0.00002, 28981.7\n",
"-6095.26484693, 0.00002, 28981.7\"\"\""
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 146
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We can do much the same as before:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"data = []\n",
"for line in csv.splitlines():\n",
" words = line.split(',')\n",
" data.append(list(map(float,words)))\n",
"data = array(data)"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 147
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"There are two significant changes over what we did earlier. First, I'm passing the comma character ',' into the split function, so that it breaks to a new word every time it sees a comma. Next, to simplify things a big, I'm using the **map()** command to repeatedly apply a single function (**float()**) to a list, and to return the output as a list."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"help(map)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"Help on class map in module builtins:\n",
"\n",
"class map(object)\n",
" | map(func, *iterables) --> map object\n",
" | \n",
" | Make an iterator that computes the function using arguments from\n",
" | each of the iterables. Stops when the shortest iterable is exhausted.\n",
" | \n",
" | Methods defined here:\n",
" | \n",
" | __getattribute__(...)\n",
" | x.__getattribute__('name') <==> x.name\n",
" | \n",
" | __iter__(...)\n",
" | x.__iter__() <==> iter(x)\n",
" | \n",
" | __next__(...)\n",
" | x.__next__() <==> next(x)\n",
" | \n",
" | ----------------------------------------------------------------------\n",
" | Data and other attributes defined here:\n",
" | \n",
" | __new__ = <built-in method __new__ of type object>\n",
" | T.__new__(S, ...) -> a new object with type S, a subtype of T\n",
"\n"
]
}
],
"prompt_number": 148
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Despite the differences, the resulting plot should be the same:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"plot(data[:,0])\n",
"xlabel('step')\n",
"ylabel('Energy (hartrees)')\n",
"title('Convergence of NWChem geometry optimization for Si cluster')"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 149,
"text": [
"<matplotlib.text.Text at 0x7830810>"
]
},
{
"output_type": "display_data",
"png": "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\n"
}
],
"prompt_number": 149
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Hartrees (what most quantum chemistry programs use by default) are really stupid units. We really want this in kcal/mol or eV or something we use. So let's quickly replot this in terms of eV above the minimum energy, which will give us a much more useful plot:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"energies = data[:,0]\n",
"minE = min(energies)\n",
"energies_eV = 27.211*(energies-minE)\n",
"plot(energies_eV)\n",
"xlabel('step')\n",
"ylabel('Energy (eV)')\n",
"title('Convergence of NWChem geometry optimization for Si cluster')"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 150,
"text": [
"<matplotlib.text.Text at 0x7142e50>"
]
},
{
"output_type": "display_data",
"png": "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\ntGny7LPPiojIkiVL5K9//au8//77BrcNGzasyc/tvHnzxNHRUdLT06WqqkrmzJkjd955p4jo3mz1\n6dNH/u///k8qKirk1KlTctttt8l///tfg/t+9dVXotVqZcqUKRIcHCwLFy4UrVYr77//voSGhtb5\nuDdv3pSgoCBZvny5aLVa2bRpkzg4OOiPT33Hvby8XMrLy6Vr166yaNEiqaiokJ07d4qrq6v8+uuv\nIqIL886dO8vBgwelrKxMhg4dKsHBwbJu3TqpqqqSuXPnypAhQ5q0jykpKTJ58mSD2mNjYyU4OFh+\n/vlnqayslJs3b4qXl5f88ssv+nUiIyNl06ZNde774MGD5emnn5abN2/KoUOHxNvbW3bu3Kk/pvb2\n9vLvf/9btFqtLF26VEJDQ0Wr1YqISEhIiMEbwbrCPCwsTE6dOiVXr16ViIgI6datm+zYsUP/HE2b\nNk1//+owv9Wjjz4qjzzyiIjownz79u1SXl4uFy5ckLvvvltmz56tX7exmhrb3/pef3W59bGaciw3\nb94sIiKlpaW1tnfPPffIXXfdJRs2bJAzZ84YLGsozLVarfTq1Uuef/55KSkpkbKyMtm9e7eINB7m\ncXFx+jcWCQkJsnDhQhHR/U1Ub0Ok9nPT0N+EiC7Mo6KiJC8vT8rKyuo9hkrBMG+mjz/+WLp06dLg\nOl27djVoxf73v/+VkJAQEdGFeceOHQ1erD4+PrJ3714REZk7d6489thjIiJy7do1cXZ2lpycHBER\nCQ8PN/jDLCgoEHt7e6msrNT/EZw+fVq/fMiQIbJq1Sr99e3bt+v/UM6dOycdOnQw+IP99NNP9f+0\nV69eLd26ddMvu3HjhqhUKiksLJSCggKxsbHRvwGpacaMGbUC+Pbbb9e3nGtau3atREdHG9w2cOBA\n+eijj0Tk97CuT3XYVwddenp6rTD/6KOPJCoqSkRE4uPjZfv27XLs2DGD21599VURadpzO2/ePBk+\nfLj++tGjR6Vjx44ioutZCQoKMlh/4cKF+jCYN2+ejBgxQr8sNTVVXFxc9D0x165dE5VKJVevXq31\nuN9++62o1WqD2wYNGqQ/1g0d9127dtXar8TERElJSRERXZg/+eST+mV/+9vfJCIiQn/98OHD4uHh\n0eR9nDRpksHyuLg4mTdvnsFtM2bMkJdffllERH766Sfx9PTU/5OtKScnR2xtbaW4uFh/25w5c2Tq\n1Kn6xxs4cKB+WVVVlfj5+cn3338vIo0HZ1xcnD4cRET+9Kc/yciRI/XXt2zZou9hEKk7zF9//XXp\n169fvYHwxRdf6F9vjdXUlP2t7/VXl5qP1ZRtx8bG1rstEZErV67IX/7yF+nRo4fY2tpKZGSk/PDD\nD7X241Z79uwRb2/vOpc1J8ynTJkiTz75pOTl5dXazq3PTX1/E9UNj5CQEH2vqCXgZ+bN1KlTJ1y8\neBFVVVX1rlNQUIDg4GD99aCgIBQUFBhso3qQFgA4OTmhuLgYAJCYmIhNmzahvLwcmzZtQt++fREY\nGAgAyM7OxpgxY+Dp6QlPT09ERETAzs4OhYWF+m1VrwsAZ8+eNbgeEBCg//3MmTOoqKiAn5+ffnsz\nZszAhQsX9Ot06dLFoEYAKC4uRm5uLry8vODu7l5r38+cOYM333xTv01PT0/k5eXh7NmzdR6noKAg\ng9uCg4MNjlVTODg44JVXXsErr7xSa/DN4MGDcfjwYRQVFWHv3r0YOHAgbr/9dpw9exZFRUXYvXs3\n7r77bgBNe24BGHxG6OTkhLKyMlRVVeHMmTMoKCgw2PdFixbh/Pnz+vV9fHz0v3fs2BGdO3fW19yx\nY0cA0L8WaiooKIBarTa4reZz29BxLygoMFgXMDzOKpXKoC5HR8dadVbX1JR9rMutj5+UlIRPP/0U\nALBu3To8/PDDsLe3r3O/vby84OzsrL8tKCgI+fn5+us1X9cqlQoBAQHNeg3VfD5v3XdHR8c6n49q\n6enpWL58Ob788kt06NABgG4WRkJCAgICAuDu7o7Jkyfrx200pin7W9/rry22XfNY1sXDwwOLFi3C\nTz/9hMLCQkRGRmL06NGNPnZubi6Cg4MN/u+1xBtvvAERwYABA3DHHXdg9erV9a5b399EzdfGra9L\nJWOYN9PAgQPRoUMHfPHFF/Wu4+/vbzB9JScnB/7+/k3afkREBIKDg5Geno5PP/0UjzzyiH5ZUFAQ\ntm3bhitXrugvJSUl8PPz069TM8z8/PyQm5urv17z98DAQHTo0AGXLl3Sb+vq1as4cuRIozUGBgbi\n8uXLuHr1aq1lQUFBePnllw1qLC4uxsMPP1xrXbVajTNnzhjcdubMmVqh1RD5bcDL1KlTUVRUhH//\n+98Gy2+77Tb4+/tj1apVCAoK0r8pGThwIFauXIni4mLceeed+tsae24bGqkbGBiI0NBQg32/du0a\ntm7d2uh9G+Pn52fwTxfQva6qNXTc/f39kZubazA4qLnHuVpj+1jfP+tb9/3OO++Eg4MDdu3ahfXr\n19c7At7f3x+XL182CNScnByD0Kn5uq6qqkJeXp7+7625x7w56//666+YOnUq/vWvfxkcy5deegm2\ntrb46aefcPXqVaxbt84gbBt6jKbsb0s1ZdvN2f9OnTrhT3/6EwoKCnDlypUG1w0MDEROTk6dg+pq\nqn6jUVJSor/t3Llz+t99fX2xatUq5OfnY+XKlXjqqafqHcHelP9FljQ7hWHeTO7u7nj11Vfx9NNP\nY/PmzSgpKUFFRQXS09Px4osvAtC1rhcsWICLFy/i4sWLePXVV5s1XeeRRx7B22+/je+++w4TJkzQ\n3z5jxgy89NJL+n/iFy5caHAE/cSJE/HOO++goKAARUVFWLx4sf7F6+fnhxEjRuD555/H9evXUVVV\nhZMnT2LXrl2N1ufn54f7778fTz31FIqKilBRUaG/3xNPPIF//OMf2LdvH0QEN27cwH/+8586Wzcj\nR47E8ePHsX79emi1Wnz22Wc4duwYHnzwQQCNj0ytudzOzg7z5883mGJWbfDgwVi2bJm+BQ4AgwYN\nwrJly9C/f399i6opz21DNQ0YMACurq544403UFpaisrKSvz000/Yv39/k/anITExMbC1tcW7774L\nrVaLzZs3G0zJa+i433nnnXBycsIbb7yBiooKaDQabN26FQkJCc2uq7F99PX1RXZ2dq1t1vUYkydP\nxsyZM+Hg4ICYmJg6Hy8wMBAxMTGYM2cObt68icOHD+PDDz/EpEmT9OscOHAAX3zxBbRaLd5++204\nOjrq36D5+vri5MmTDe5TzdqaeiyuXbuGhx56CK+99lqt2ouLi+Hs7Aw3Nzfk5+fXmlbZUE1N2d+W\naottv/jiizh69Ci0Wi2uX7+OFStWICwsDJ6eng3eLzo6Gn5+fvjLX/6CkpISlJWVYc+ePbXW8/b2\nhlqtxrp161BZWYkPP/zQ4Fj961//Ql5eHgBdL4FKpdK/gbz1uDbnf5ElYJi3wPPPP49ly5ZhwYIF\n8PHxQVBQEP7+979jzJgxAIC5c+eiX79+6NWrF3r16oV+/foZTJ9q7N1gYmIidu3ahWHDhsHLy0t/\n+7PPPov4+HiMGDECbm5uGDhwIPbt21fvdp944gmMGDECvXr1Qt++ffHAAw/A1tZW/+Jfu3YtysvL\nERERAS8vL0yYMEH/LlilUtXaXs3r69atg729Pbp37w5fX18sX74cANC3b1+8//77mDlzJry8vBAW\nFoa1a9fWuZ9eXl7YunUr3nzzTXTu3BlLly7F1q1b9ftcVw231lNzeWJiIvz9/WvdJzY2FhcuXMCg\nQYP0tw0ePBgXLlwwCHig8ee2oeNia2uLrVu34tChQ7jtttvg7e2NJ598EteuXWvSMa3rejV7e3ts\n2rQJH3zwATw9PfHJJ5/gwQcfhIODA4CGj7u9vT22bNmC9PR0eHt7Y+bMmVi3bh3+8Ic/1FlXa/ax\n+s1np06d0K9fvwb3a/LkyTh69GijYbJ+/XpkZ2fD398fY8eOxauvvoqhQ4fqt/vQQw/hs88+g5eX\nFz755BNs2rQJtra2AIA5c+ZgwYIF8PT0xLJlyxo95o09R9W/Hzx4EMePH8dzzz0HV1dXuLq6ws3N\nDQAwb948HDx4EO7u7hg1ahTGjRtnsI3Gampsf5v6mmnJsWxsW6WlpfqP+rp27Yrc3FyDBkV997ex\nscGWLVtw4sQJBAUFITAwEJ9//nmdj/v+++9jyZIl6Ny5M37++Wfcdddd+mX79+/HnXfeCVdXVzz0\n0ENYvny5ft5/SkoKkpKS4OnpiY0bN9b7N2FJrfGaVNKa5gIpSnp6OpKTk9v8DFZkGtHR0XjqqaeQ\nlJRk6lJapLS0FL6+vsjMzETXrl1btI358+fjxIkTWLduXRtXR6QsRm+ZV1ZWIioqCqNGjapz+axZ\nsxAWFobevXsjMzPT2OVYlbKyMqSlpUGr1SI/Px/z58/H2LFjTV0WtdCuXbtw7tw5aLVarFmzBj/9\n9BPuu+8+U5fVYitWrMCAAQNaHOQAT+JDVM3O2A/wzjvvICIiAtevX6+1LC0tDSdOnEBWVhb27t2L\n5ORkZGRkGLskqyEiSElJQUJCAjp27IgHH3wQr776qqnLohb69ddfMXHiRNy4cQNdu3bFxo0bzers\nW80REhIClUqFL7/8slXbaUrXMJE1MGo3e15eHqZOnYqXX34Zy5Yt058Ss9qMGTMwZMgQ/ejC7t27\n49tvv1XsPygiIiJTMGrL/LnnnsOSJUv0g2NulZ+fX2sedF5enkGY8103ERFZm+a2s432mfnWrVvh\n4+ODqKioBou6dVld4S2/fTkDL/Vf5s2bZ/IalHLhseJx4rHicTLnS0sYLcz37NmD1NRUhIaGIjEx\nETt37sSUKVMM1lGr1QYnfMjLy2vRiSyIiIismdHCfOHChcjNzcXp06exYcMGDB06tNZ84/j4eP1t\nGRkZ8PDw4OflREREzWT00ezVqrvPV65cCQCYPn06Ro4cibS0NHTr1g3Ozs4NnmeXGhYXF2fqEhSD\nx6ppeJyajseqaXicjMfsTxqjUqla/BkCERGR0rQk93g6VyIiIoVjmBMRESkcw5yIiEjhGOZEREQK\nxzAnIiJSOIY5ERGRwjHMiYiIFI5hTkREpHAMcyIiIoVjmBMRESkcw5yIiEjhFBHmt3zZGhEREdWg\niDD/7jtTV0BERGS+FBHmZ86YugIiIiLzpYgwz842dQVERETmSxHfZ96hg6CkBLBRxFsPIiKilrPY\n7zN3cwMKC01dBRERkXlSRJiHhLCrnYiIqD6KCPPgYA6CIyIiqo8iwpwtcyIiovopIsyDgxnmRERE\n9VFEmIeEsJudiIioPooJc7bMiYiI6qaIeebXrgl8fYEbNwCVytQVERERGY/FzjN3dQU6dgQuXDB1\nJUREROZHEWEOsKudiIioPooJc841JyIiqptiwpwtcyIioroxzImIiBROMWHObnYiIqK6KSbM2TIn\nIiKqm2LCvPqUruY9K56IiKj9KSbMPTwAOzvg8mVTV0JERGRejBbmZWVliI6ORmRkJCIiIjBnzpxa\n62g0Gri7uyMqKgpRUVFYsGBBg9tkVzsREVFtdsbasKOjI7755hs4OTlBq9Vi0KBB+P777zFo0CCD\n9WJjY5GamtqkbVYPguvb1xgVExERKZPRwhwAnJycAADl5eWorKyEl5dXrXWacv7ZlJQUAEBhIbB9\nexzGjo1ryzKJiIhMRqPRQKPRtGobRv2ilaqqKvTp0wcnT55EcnIy3njjDYPl3377LcaOHYuAgACo\n1WosXboUERERhgXWOOH8W28Bp08Dy5cbq2IiIiLTMrsvWrGxscGhQ4eQl5eHXbt21Xrn0adPH+Tm\n5uLHH3/EM888g9GjRze4Pc41JyIiqq1dRrO7u7vjgQcewP79+w1ud3V11XfF33///aioqMDlBoar\ncwAcERFRbUYL84sXL6KoqAgAUFpaiq+//hpRUVEG6xQWFuq7Evbt2wcRqfNz9WrVc82JiIjod0Yb\nAHf27FkkJSWhqqoKVVVVmDx5MoYNG4aVK1cCAKZPn46NGzdixYoVsLOzg5OTEzZs2NDgNr28gKoq\noKhIN++ciIiIjDwAri3cOhCgZ09g3TogMtKERRERERmJ2Q2AMwZ2tRMRERlSXJiHhHBEOxERUU2K\nDHO2zImIiH6nuDDnXHMiIiJDigtztsyJiIgMMcyJiIgUTnFh3rkzcPMmcO2aqSshIiIyD4oLc5WK\nn5sTERHVpLgwBzjXnIiIqCZFhjnnmhMREf1OsWHOljkREZGOIsOcn5kTERH9TpFhzpY5ERHR7xjm\nRERECqfIMPfxAYqLgRs3TF0JERGR6SkyzG1sgKAgfm5OREQEKDTMAc41JyIiqqbYMOdccyIiIh1F\nhzlb5kRERAoOc3azExER6Sg2zNnNTkREpKPoMGfLnIiICFCJiJi6iIaoVCrUVWJVFdCxI1BUpPtJ\nRERkCerLvYYotmVuYwMEBgI5OaauhIiIyLQUG+YAu9qJiIgAhYc5vz2NiIhI4WHOljkREZHCw5xz\nzYmIiBQe5pxrTkREZAFhzpY5ERFZO8XOMwcArRZwcgKuXwc6dGjnwoiIiIzAquaZA4CdHaBWA7m5\npq6EiIjIdIwW5mVlZYiOjkZkZCQiIiIwZ86cOtebNWsWwsLC0Lt3b2RmZjb7cdjVTkRE1s7OWBt2\ndHTEN998AycnJ2i1WgwaNAjff/89Bg0apF8nLS0NJ06cQFZWFvbu3Yvk5GRkZGQ063E415yIiKyd\nUbvZnZycAADl5eWorKyEl5eXwfLU1FQkJSUBAKKjo1FUVITCwsJmPQZb5kREZO2M1jIHgKqqKvTp\n0wcnT55EcnIyIiIiDJbn5+cjMDBQfz0gIAB5eXnw9fU1WC8lJUX/e1xcHOLi4vTXg4OBnTuNUj4R\nEZHRaTQaaDSaVm3DqGFuY2ODQ4cO4erVq7j33nuh0WgMghhArRF7KpWq1nZqhvmtONeciIiU7NZG\n6vz585u9jXYZze7u7o4HHngA+/fvN7hdrVYjt8ZQ9Ly8PKjV6mZtm93sRERk7YwW5hcvXkRRUREA\noLS0FF9//TWioqIM1omPj8fatWsBABkZGfDw8KjVxd6YgADg3DmgoqJt6iYiIlIao3Wznz17FklJ\nSaiqqkJVVRUmT56MYcOGYeXKlQCA6dOnY+TIkUhLS0O3bt3g7OyM1atXN/tx7O2BLl2AvDwgNLSt\n94KIiMj8KfoMcNXuvhuYPx8YMqSdiiIiIjISqzsDXDXONSciImtmEWHOQXBERGTNGOZEREQKZxFh\nzm52IiKyZhYR5myZExGRNbOI0ew3bwKurkBJie5rUYmIiJTKakezd+gAeHsDBQWmroSIiKj9WUSY\nA+xqJyIi62UxYc5BcEREZK0sJszZMiciImvFMCciIlI4iwlzdrMTEZG1spgwZ8uciIislUXMMweA\n0lLAw0P308Zi3qIQEZG1sdp55gDQsSPg6QmcPWvqSoiIiNqXxYQ5wK52IiKyThYV5sHBDHMiIrI+\nFhXmISEc0U5ERNbH4sKcLXMiIrI2FhXmnGtORETWyKLCnC1zIiKyRhYzzxwAbtwAOnfW/eRccyIi\nUiKrnmcOAM7OgIsLcP68qSshIiJqPxYV5gC72omIyPpYXJhzrjkREVkbiwtzzjUnIiJrY5FhzpY5\nERFZE4sLc841JyIia2NxYc6WORERWRuLmmcOANeuAX5+QHExoFIZsTAiIiIjsPp55gDg5gZ06ABc\nvGjqSoiIiNqHxYU5wK52IiKyLhYZ5pxrTkRE1sRoYZ6bm4shQ4agR48euOOOO7B8+fJa62g0Gri7\nuyMqKgpRUVFYsGBBmzw255oTEZE1sTPWhu3t7fHWW28hMjISxcXF6Nu3L4YPH47w8HCD9WJjY5Ga\nmtqmjx0SAmRltekmiYiIzJbRWuZdunRBZGQkAMDFxQXh4eEoKCiotZ4xBtOzm52IiKyJ0VrmNWVn\nZyMzMxPR0dEGt6tUKuzZswe9e/eGWq3G0qVLERERUev+KSkp+t/j4uIQFxfX4OOxm52IiJRCo9FA\no9G0ahtGn2deXFyMuLg4zJ07F6NHjzZYdv36ddja2sLJyQnp6el49tlncfz4ccMCWzDfrqgICAzU\nzTnnXHMiIlISs5tnXlFRgXHjxmHSpEm1ghwAXF1d4eTkBAC4//77UVFRgcuXL7f6cT08ABsb4MqV\nVm+KiIjI7BktzEUEjz/+OCIiIjB79uw61yksLNS/+9i3bx9EBF5eXm3y+JxrTkRE1sJon5nv3r0b\nH3/8MXr16oWoqCgAwMKFC5GTkwMAmD59OjZu3IgVK1bAzs4OTk5O2LBhQ5s9fnWY9+nTZpskIiIy\nSxZ3bvZqs2YBoaHAc88ZoSgiIiIjMbvPzE2J3exERGQtLDbMOdeciIishcWGOeeaExGRtbDoMGfL\nnIiIrIHFhrmXF6DV6k4gQ0REZMksNsxVKna1ExGRdbDYMAfY1U5ERNbBosM8OJgtcyIisnxNDvOy\nsjLcvHnTmLW0ObbMiYjIGtQb5lVVVdi0aRMmTJgAtVqN0NBQBAcHQ61WY/z48fjiiy+M8l3kbYlz\nzYmIyBrDFppJAAAcK0lEQVTUG+ZxcXE4cOAAXnjhBZw6dQpnz57FuXPncOrUKbzwwgv44YcfEBsb\n2561NhsHwBERkTWo99zs5eXlcHBwaPDON2/eRIcOHYxSWLWWnpsdAM6fB8LDgUuX2rgoIiIiI2nT\nc7OPHj0aH3/8MYqLi+u9s7GDvLW8vYHSUuD6dVNXQkREZDz1hvmTTz6JrVu3IjQ0FBMnTsQXX3yB\n8vLy9qyt1VQqjmgnIiLL12DLfMOGDcjOzsbYsWOxZs0aBAYGYtq0afjqq6/as8ZW4Yh2IiKydM36\nPvMff/wRSUlJOHLkCCorK41Zl15rPjMHgBkzgJ49gaefbsOiiIiIjMQo32d+7tw5LF++HDExMRg9\nejTuu+8+HDx4sMVFtje2zImIyNLZ1bdg1apV2LBhA44dO4Zx48Zh6dKlGDhwIFQqVXvW12ohIcCB\nA6augoiIyHjqDfP//e9/mDNnDoYOHQpbW9v2rKlNcQAcERFZukY/M6+qqsInn3yC06dP469//Sty\ncnJw7tw5DBgwoH0KbOVn5mfPAr176+acExERmbuW5F6jYT5jxgzY2Nhg586dOHbsGC5fvowRI0Zg\n//79rSq2yQW2MsyrqgAnJ92JY5yd27AwIiIiIzDKALi9e/fi73//Ozp27AgA8PLyQkVFRcsqNAEb\nGyAoCMjJMXUlRERExtFomDs4OBhMQ7tw4QJsbJT1zakc0U5ERJas0VR+5plnMGbMGJw/fx4vvfQS\n7rrrLsyZM6c9amszHARHRESWrN7R7NUmTZqEvn37YseOHQCAzZs3Izw83OiFtSW2zImIyJLVG+bX\nr1+Hq6srACA8PLzOAK+5jjkLCQG2bDF1FURERMZRb5iPGTMGt99+Ox566CH069cPXl5eAIDLly/j\nhx9+wJdffomsrCxs37693YptKXazExGRJWtwatrOnTvx6aefYvfu3SgoKAAA+Pv7Y9CgQXj00UcR\nFxdn/AJbOTUNAPLygP79dXPOiYiIzJlR5pmbWluEeWWlbq751auAo2MbFUZERGQERplnbglsbYGA\nAM41JyIiy2QVYQ5wRDsREVkuqwnz4GCGORERWaZGw/z555/H0aNH26MWowoJ4Yh2IiKyTI2GeXh4\nOJ588kkMGDAA//jHP3D16tUmbTg3NxdDhgxBjx49cMcdd2D58uV1rjdr1iyEhYWhd+/eyMzMbF71\nzcBudiIislSNhvkTTzyB3bt3Y+3atcjOzkbPnj3xyCOP4Jtvvmnwfvb29njrrbdw9OhRZGRk4L33\n3sMvv/xisE5aWhpOnDiBrKwsrFq1CsnJya3bmwZwrjkREVmqJn1mXllZiWPHjuGXX36Bt7c3evfu\njWXLluHhhx+u9z5dunRBZGQkAMDFxQXh4eH6uerVUlNTkZSUBACIjo5GUVERCgsLW7ovDWLLnIiI\nLFWj52Z/7rnnsGXLFgwdOhQvv/wyBgwYAAB48cUXcfvttzfpQbKzs5GZmYno6GiD2/Pz8xEYGKi/\nHhAQgLy8PPj6+hqsl5KSov89Li6uRSerUauB8+eB8nLAwaHZdyciIjIKjUYDjUbTqm00Gua9evXC\nggUL4OzsXGvZ3r17G32A4uJijB8/Hu+88w5cXFxqLb91YrxKpaq1Ts0wbyk7O8DfH8jNBbp2bfXm\niIiI2sStjdT58+c3extNCvNff/3V4DZ3d3cEBwfDw8OjwftWVFRg3LhxmDRpEkaPHl1ruVqtRm5u\nrv56Xl4e1Gp1U2tvtuqudoY5ERFZkkbD/Omnn8aBAwfQq1cvAMCRI0fQo0cPXL16FStWrMC9995b\n5/1EBI8//jgiIiIwe/bsOteJj4/Hu+++i4SEBGRkZMDDw6NWF3tb4lxzIiKyRI0OgPP398ehQ4dw\n4MABHDhwAIcOHcJtt92Gr7/+Gv/v//2/eu+3e/dufPzxx/jmm28QFRWFqKgopKenY+XKlVi5ciUA\nYOTIkbjtttvQrVs3TJ8+HX//+9/bbs/qwLnmRERkiRptmf/666/o0aOH/npERASOHTuGrl271vn5\ndrVBgwahqqqq0QLefffdJpbaeiEhQCMz6oiIiBSn0TDv0aMHkpOTkZCQABHB559/joiICNy8eRP2\n9vbtUWOb4VxzIiKyRI1+BWppaSnee+897N69GwBw11134amnnoKjoyNu3LgBV1dX4xbYBl+BWu3U\nKWDIEAY6ERGZrzb/PnOtVovhw4c3erY3Y2rLMC8vB1xcgBs3AIV1KhARkZVo8+8zt7Ozg42NDYqK\nilpVmLlwcAB8fYH8fFNXQkRE1HYa/czc2dkZPXv2xPDhw/UnjlGpVPV+cYq5q55rHhJi4kKIiIja\nSKNhPnbsWIwdO1Y/cl1EGhzFbu54jnYiIrI0jYb51KlTUVJSgpycHHTv3r09ajIqjmgnIiJL0+hJ\nY1JTUxEVFYX77rsPAJCZmYn4+HijF2YsbJkTEZGlaTTMU1JSsHfvXnh6egIAoqKicOrUKaMXZiw8\npSsREVmaRsPc3t6+1heq2Ng06WvQzRJP6UpERJam0VTu0aMHPvnkE2i1WmRlZeGZZ55BTExMe9Rm\nFEFBuqlplZWmroSIiKhtNBrmf/vb33D06FF06NABiYmJcHNzw9tvv90etRlFhw5Ap05AQYGpKyEi\nImobjZ7O1dTa8gxw1WJigMWLgcGD23SzRERErdaS3GvSt6YtXboU2dnZ0Gq1+gfauXNny6o0A9Uj\n2hnmRERkCRoN8wkTJiA5ORl//OMfYWtrCwCKPmkMwLnmRERkWRoNc3t7eyQnJ7dHLe0mJAT44QdT\nV0FERNQ2Gh0AN2rUKLz33ns4e/YsLl++rL8oGeeaExGRJWl0AFxISEid3eqnT582WlE1GWMA3LFj\nwKhRQFZWm26WiIio1dr8+8zNgTHCvLQU8PQESkoABZ//hoiILFCbfp/5G2+8of/9X//6l8Gyl156\nqZmlmZeOHQF3d+DcOVNXQkRE1Hr1hvn69ev1vy9cuNBgWXp6uvEqaif8whUiIrIUVtvJzDAnIiJL\nYbVhzrnmRERkKeqdZ3748GG4uroCAEpLS/W/V19XupAQ4McfTV0FERFR69Ub5pUW/rViISHA5s2m\nroKIiKj12M1ORESkcFY5zxwAiosBb2/dXHOFn2qeiIgsSJvOM7d0Li6AszNQWGjqSoiIiFrHasMc\n0H1uzq52IiJSOqsPc841JyIipbPqMOcgOCIisgRWHeZsmRMRkSVgmGebugoiIqLWMWqYP/bYY/D1\n9UXPnj3rXK7RaODu7o6oqChERUVhwYIFxiynFnazExGRJaj3DHBtYdq0aXjmmWcwZcqUeteJjY1F\namqqMcuoV3CwrmUuwrnmRESkXEZtmQ8ePBienp4NrmPKc9a4uwMODsDFiyYrgYiIqNWM2jJvjEql\nwp49e9C7d2+o1WosXboUERERtdZLSUnR/x4XF4e4uLg2q6F6rrm3d5ttkoiIqMk0Gg00Gk2rtmH0\n07lmZ2dj1KhROHLkSK1l169fh62tLZycnJCeno5nn30Wx48fNyzQSKdzrTZmDPDoo8D48UZ7CCIi\noiZT3OlcXV1d4eTkBAC4//77UVFRgcuXL7drDRwER0RESmfSMC8sLNS/+9i3bx9EBF5eXu1aA6en\nERGR0hn1M/PExER8++23uHjxIgIDAzF//nxUVFQAAKZPn46NGzdixYoVsLOzg5OTEzZs2GDMcuoU\nEgLs2NHuD0tERNRmrPYrUKtlZgJJScDhw0Z7CCIioiZT3Gfm5qC6m92839IQERHVz+rD3MNDd8KY\nK1dMXQkREVHLWH2Yq1Qc0U5ERMpm9WEOcEQ7EREpG8Mcv5+jnYiISIkY5vj9lK5ERERKxDAHu9mJ\niEjZGObgADgiIlI2hjnYMiciImVjmAPo1AmoqACuXjV1JURERM3HMAfnmhMRkbIxzH/DrnYiIlIq\nhvlvONeciIiUimH+G841JyIipWKY/4bd7EREpFQM899wABwRESkVw/w3bJkTEZFSMcx/4+MDlJQA\nxcWmroSIiKh5GOa/UamAoCB2tRMRkfIwzGtgVzsRESkRw7wGhjkRESkRw7wGjmgnIiIlYpjXwJY5\nEREpEcO8Bp7SlYiIlIhhXgNP6UpEREqkEhExdRENUalUaK8Sq6oAJyfg8mXdTyIiovbWktxjy7wG\nGxsgMBDIyTF1JURERE3HML8FB8EREZHSMMxvwTAnIiKlYZjfgnPNiYhIaRjmt2DLnIiIlIZhfgvO\nNSciIqVhmN+Cc82JiEhpjBbmjz32GHx9fdGzZ89615k1axbCwsLQu3dvZGZmGquUZvH3By5dAsrK\nTF0JERFR0xgtzKdNm4Zt27bVuzwtLQ0nTpxAVlYWVq1aheTkZGOV0iy2toBaDeTmmroSIiKipjFa\nmA8ePBienp71Lk9NTUVSUhIAIDo6GkVFRSgsLDRWOc3CQXBERKQkdqZ64Pz8fAQGBuqvBwQEIC8v\nD76+vrXWTUlJ0f8eFxeHuLg4o9bGMCciovai0Wig0WhatQ2ThTmAWueeValUda5XM8zbA+eaExFR\ne7m1kTp//vxmb8Nko9nVajVya3wwnZeXB7VabapyDLBlTkRESmKyMI+Pj8fatWsBABkZGfDw8Kiz\ni90UGOZERKQkRutmT0xMxLfffouLFy8iMDAQ8+fPR0VFBQBg+vTpGDlyJNLS0tCtWzc4Oztj9erV\nxiql2djNTkRESsLvM6+DVqv7PvPiYsDBoV0fmoiIrBy/z7yN2NkBfn6ca05ERMrAMK8HT+tKRERK\nwTCvBwfBERGRUjDM68FBcEREpBQM83qwZU5ERErBMK8Hw5yIiJSCYV4PdrMTEZFScJ55PcrLARcX\noKREN1WNiIioPXCeeRtycAB8fIC8PFNXQkRE1DCGeQM415yIiJSAYd4ADoIjIiIlYJg3gIPgiIhI\nCRjmDWDLnIiIlIBh3gCGORERKQHDvAHsZiciIiXgPPMGlJUB7u66uea2tiYpgYiIrAznmbcxR0eg\nUyegoMDUlRAREdWPYd4IdrUTEZG5Y5g3goPgiIjI3DHMGxEczDAnIiLzxjBvBE/pSkRE5o5h3gh2\nsxMRkbljmDeCA+CIiMjccZ55I0pKAC8v3U8bvvUhIiIj4zxzI3By0p045tw5U1dCRERUN4Z5E7Cr\nnYiIzBnDvAk4CI6IiMwZw7wJONeciIjMGcO8CTjXnIiIzBnDvAnYzU5EROaMYd4EHABHRETmjPPM\nm+D6dcDXF7hxA1CpTFoKERFZOM4zNxJXV9188/PnTV0JERFRbUYN823btqF79+4ICwvD4sWLay3X\naDRwd3dHVFQUoqKisGDBAmOW0yrsaiciInNlZ6wNV1ZWYubMmdi+fTvUajX69++P+Ph4hIeHG6wX\nGxuL1NRUY5XRZqoHwQ0YYOpKiIiIDBktzPft24du3bohJCQEAJCQkIDNmzfXCvOmfC6QkpKi/z0u\nLg5xcXFtWGnTcEQ7EREZg0ajgUajadU2jBbm+fn5CAwM1F8PCAjA3r17DdZRqVTYs2cPevfuDbVa\njaVLlyIiIqLWtmqGuakEBwO//mrqKoiIyNLc2kidP39+s7dhtDBXNWHYd58+fZCbmwsnJyekp6dj\n9OjROH78uLFKapWQEOC//zV1FURERLUZbQCcWq1Gbm6u/npubi4CAgIM1nF1dYWTkxMA4P7770dF\nRQUuX75srJJahad0JSIic2W0MO/Xrx+ysrKQnZ2N8vJyfPbZZ4iPjzdYp7CwUP+Z+b59+yAi8PLy\nMlZJrVI9mt28Z+UTEZE1Mlo3u52dHd59913ce++9qKysxOOPP47w8HCsXLkSADB9+nRs3LgRK1as\ngJ2dHZycnLBhwwZjldNqHh6AvT1w6RLQubOpqyEiIvodzwDXDJGRwAcfAH37mroSIiKyVDwDnJFx\nehoREZkjhnkzMMyJiMgcMcybgad0JSIic8Qwbwa2zImIyBwxzJuBc82JiMgcMcybISSEc82JiMj8\nMMybwdNTF+RFRaauhIiI6HcM82ZQqTgIjoiIzA/DvJk4CI6IiMwNw7yZGOZERGRuGObNxG52IiIy\nNwzzZmLLnIiIzA3DvJkY5kREZG4Y5s3EbnYiIjI3DPNm6twZuHkTuHrV1JUQERHpMMybiXPNiYjI\n3DDMW6D6tK5ERETmgGHeAhwER0RE5oRh3gLsZiciInPCMG+BkBBgxw5gzx6gqsrU1RARkbWzM3UB\nSvTQQ0BWFvDEE0BxMfDww0BCAhAVpRsgR0RE1J5UIub97dwqlQrmWqII8NNPwIYNuoudnS7UExKA\n8HBTV0dERErUktxjmLcREeCHH3Sh/tlngLe3LtQffhgIDTV1dUREpBQMczNRVQV8/z2wfj2wcSPQ\ntSuQmAhMmAD4+5u6OiIiMmcMczNUUQHs3KlrsW/eDPTurQv2ceOATp1MXR0REZkbhrmZKysDtm3T\nBXt6OnDXXbqu+NGjATc3U1dHRETmgGGuIMXFwJYtumDXaIB77tEF+wMPAE5Opq6OiIhMhWGuUFeu\nAF9+qfuMfd8+4MEHdcE+YgTg4GDq6oiIqD0xzC3A+fO6QXPr1wM//wyMGaP7jD0uDrC1NXV1RERk\nbAxzC5ObC3z+ua4rPjdXNxo+MRG4807AhufuIyKySAxzC5aVpZu/vn49zzpHRGTJWpJ7bN8pRFgY\nMHcucPQo8J//APb2upZ69+7AvHnAmjUaU5eoGBqNxtQlKAKPU9PxWDUNj5Px8NzsCnTHHcBrrwEL\nFgD79+u64Z95RoOFC+Pg5wd4eDT94uZmfV32Go0GcXFxpi7D7PE4NR2PVdPwOBmPUcN827ZtmD17\nNiorK/HHP/4RL774Yq11Zs2ahfT0dDg5OeGjjz5CVFSUMUuyKCoV0L+/7uLiAowfD1y6BBQVGV5O\nn659W/WluBhwdW3eGwBrfzNARGRujBbmlZWVmDlzJrZv3w61Wo3+/fsjPj4e4TW+gSQtLQ0nTpxA\nVlYW9u7di+TkZGRkZBirJIumUgE9ezb/fpWVwLVr9Yd9a98MuLsDjo66KXb29m37086O4wWIiAAA\nYiR79uyRe++9V3990aJFsmjRIoN1pk+fLhs2bNBfv/322+XcuXMG6wDghRdeeOGFF6u6NJfRWub5\n+fkIDAzUXw8ICMDevXsbXScvLw++vr7624Qj2YmIiBpktE87VU3s/7w1rJt6PyIiItIxWpir1Wrk\n5ubqr+fm5iIgIKDBdfLy8qBWq41VEhERkUUyWpj369cPWVlZyM7ORnl5OT777DPEx8cbrBMfH4+1\na9cCADIyMuDh4WHQxU5ERESNM9pn5nZ2dnj33Xdx7733orKyEo8//jjCw8OxcuVKAMD06dMxcuRI\npKWloVu3bnB2dsbq1auNVQ4REZHlavaQuXaUnp4ut99+u3Tr1k1ef/11U5djtnJyciQuLk4iIiKk\nR48e8s4775i6JLOm1WolMjJSHnzwQVOXYrauXLki48aNk+7du0t4eLj873//M3VJZmvhwoUSEREh\nd9xxhyQmJkpZWZmpSzIL06ZNEx8fH7njjjv0t126dEnuueceCQsLk+HDh8uVK1dMWKH5qOtYvfDC\nC9K9e3fp1auXjBkzRoqKihrchtme7qN6nvq2bdvw888/Y/369fjll19MXZZZsre3x1tvvYWjR48i\nIyMD7733Ho9VA9555x1ERERwsGUDnn32WYwcORK//PILDh8+bHB+CPpddnY23n//fRw8eBBHjhxB\nZWUlNmzYYOqyzMK0adOwbds2g9tef/11DB8+HMePH8ewYcPw+uuvm6g681LXsRoxYgSOHj2KH3/8\nEX/4wx+waNGiBrdhtmG+b98+dOvWDSEhIbC3t0dCQgI2b95s6rLMUpcuXRAZGQkAcHFxQXh4OAoK\nCkxclXnKy8tDWloa/vjHP3LaYz2uXr2K7777Do899hgA3Udm7u7uJq7KPLm5ucHe3h4lJSXQarUo\nKSnhIN7fDB48GJ6enga3paamIikpCQCQlJSEL7/80hSlmZ26jtXw4cNh89vpNaOjo5GXl9fgNsw2\nzOuag56fn2/CipQhOzsbmZmZiI6ONnUpZum5557DkiVL9H8kVNvp06fh7e2NadOmoU+fPnjiiSdQ\nUlJi6rLMkpeXF/70pz8hKCgI/v7+8PDwwD333GPqssxWYWGhfpCzr68vCgsLTVyRMnz44YcYOXJk\ng+uY7X80doE2X3FxMcaPH4933nkHLi4upi7H7GzduhU+Pj6Iiopiq7wBWq0WBw8exFNPPYWDBw/C\n2dmZ3aH1OHnyJN5++21kZ2ejoKAAxcXF+OSTT0xdliKoVCr+n2+C1157DQ4ODnjkkUcaXM9sw7wp\n89TpdxUVFRg3bhwmTZqE0aNHm7ocs7Rnzx6kpqYiNDQUiYmJ2LlzJ6ZMmWLqssxOQEAAAgIC0L9/\nfwDA+PHjcfDgQRNXZZ7279+PmJgYdOrUCXZ2dhg7diz27Nlj6rLMlq+vL86dOwcAOHv2LHx8fExc\nkXn76KOPkJaW1qQ3iGYb5k2Zp046IoLHH38cERERmD17tqnLMVsLFy5Ebm4uTp8+jQ0bNmDo0KH6\n8xzQ77p06YLAwEAcP34cALB9+3b06NHDxFWZp+7duyMjIwOlpaUQEWzfvh0RERGmLstsxcfHY82a\nNQCANWvWsOHRgG3btmHJkiXYvHkzHB0dG7+DMYfbt1ZaWpr84Q9/kK5du8rChQtNXY7Z+u6770Sl\nUknv3r0lMjJSIiMjJT093dRlmTWNRiOjRo0ydRlm69ChQ9KvX78mT4uxZosXL9ZPTZsyZYqUl5eb\nuiSzkJCQIH5+fmJvby8BAQHy4YcfyqVLl2TYsGGcmnaLW4/VBx98IN26dZOgoCD9//Tk5OQGt6ES\n4YeHRERESma23exERETUNAxzIiIihWOYExERKRzDnIgAAG+//TZKS0tNXQYRtQAHwBERACA0NBT7\n9+9Hp06dTF0KETUTW+ZEVujGjRt44IEHEBkZiZ49e+LVV19FQUEBhgwZgmHDhgEAvvrqK8TExKBv\n376YOHEibty4AQAICQnBiy++iF69eiE6OhonT5405a4QERjmRFZp27ZtUKvVOHToEI4cOYLZs2fD\n398fGo0GO3bswMWLF/Haa69hx44dOHDgAPr27Ytly5YB0J2G08PDA4cPH8bMmTN5oiIiM8AwJ7JC\nvXr1wtdff42//OUv+P777+Hm5mawPCMjAz///DNiYmIQFRWFtWvXIicnR788MTERAJCQkID//e9/\n7Vo7EdVmZ+oCiKj9hYWFITMzE//5z38wd+5cDB06tNY6w4cPx6efftrotvhlGUSmx5Y5kRU6e/Ys\nHB0d8eijj+KFF15AZmYm3NzccO3aNQC670/evXu3/vPwGzduICsrS3//zz77TP8zJiam/XeAiAyw\nZU5khY4cOYI///nPsLGxgYODA1asWIE9e/bgvvvug1qtxo4dO/DRRx8hMTERN2/eBKD7KsawsDAA\nwJUrV9C7d284Ojpi/fr1ptwVIgKnphFRM4WGhuLAgQPw8vIydSlE9Bt2sxNRs/AzciLzw5Y5ERGR\nwrFlTkREpHAMcyIiIoVjmBMRESkcw5yIiEjhGOZEREQKxzAnIiJSuP8PYtkYh3/3x+8AAAAASUVO\nRK5CYII=\n"
}
],
"prompt_number": 150
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This gives us the output in a form that we can think about: 4 eV is a fairly substantial energy change (chemical bonds are roughly this magnitude of energy), and most of the energy decrease was obtained in the first geometry iteration."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We mentioned earlier that we don't have to rely on **grep** to pull out the relevant lines for us. The **string** module has a lot of useful functions we can use for this. Among them is the **startswith** function. For example:"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"lines = \"\"\"\\\n",
" ----------------------------------------\n",
" | WALL | 0.45 | 443.61 |\n",
" ----------------------------------------\n",
"\n",
"@ Step Energy Delta E Gmax Grms Xrms Xmax Walltime\n",
"@ ---- ---------------- -------- -------- -------- -------- -------- --------\n",
"@ 0 -6095.12544083 0.0D+00 0.03686 0.00936 0.00000 0.00000 1391.5\n",
" ok ok\n",
"\n",
"\n",
"\n",
" Z-matrix (autoz)\n",
" --------\n",
"\"\"\".splitlines()\n",
"\n",
"for line in lines:\n",
" if line.startswith('@'):\n",
" print line\n",
" "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"and we've successfully grabbed all of the lines that begin with the @ symbol."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The real value in a language like Python is that it makes it easy to take additional steps to analyze data in this fashion, which means you are thinking more about your data, and are more likely to see important patterns."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## More Sophisticated String Formatting and Processing\n",
"Strings are a big deal in most modern languages, and hopefully the previous sections helped underscore how versatile Python's string processing techniques are. We will continue this topic in this chapter.\n",
"\n",
"We can print out lines in Python using the print command. "
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"print(\"I have 3 errands to run\")"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"I have 3 errands to run\n"
]
}
],
"prompt_number": 151
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"In IPython we don't even need the print command, since it will display the last expression not assigned to a variable."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"\"I have 3 errands to run\""
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 152,
"text": [
"'I have 3 errands to run'"
]
}
],
"prompt_number": 152
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**print** even converts some arguments to strings for us:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"a,b,c = 1,2,3\n",
"print(\"The variables are \",1,2,3)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"The variables are 1 2 3\n"
]
}
],
"prompt_number": 153
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"As versatile as this is, you typically need more freedom over the data you print out. For example, what if we want to print a bunch of data to exactly 4 decimal places? We can do this using formatted strings.\n",
"\n",
"Formatted strings share a syntax with the C **printf** statement. We make a string that has some funny *format characters* in it, and then pass a bunch of variables into the string that fill out those characters in different ways.\n",
"\n",
"For example,"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"print(\"Pi as a decimal = %d\" % pi)\n",
"print(\"Pi as a float = %f\" % pi)\n",
"print(\"Pi with 4 decimal places = %.4f\" % pi)\n",
"print(\"Pi with overall fixed length of 10 spaces, with 6 decimal places = %10.6f\" % pi)\n",
"print(\"Pi as in exponential format = %e\" % pi)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"Pi as a decimal = 3\n",
"Pi as a float = 3.141593\n",
"Pi with 4 decimal places = 3.1416\n",
"Pi with overall fixed length of 10 spaces, with 6 decimal places = 3.141593\n",
"Pi as in exponential format = 3.141593e+00\n"
]
}
],
"prompt_number": 154
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We use a percent sign in two different ways here. First, the format character itself starts with a percent sign. %d or %i are for integers, %f is for floats, %e is for numbers in exponential formats. All of the numbers can take number immediately after the percent that specifies the total spaces used to print the number. Formats with a decimal can take an additional number after a dot . to specify the number of decimal places to print.\n",
"\n",
"The other use of the percent sign is after the string, to pipe a set of variables in. You can pass in multiple variables (if your formatting string supports it) by putting a tuple after the percent. Thus,"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"print(\"The variables specified earlier are %d, %d, and %d\" % (a,b,c))"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"The variables specified earlier are 1, 2, and 3\n"
]
}
],
"prompt_number": 155
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This is a simple formatting structure that will satisfy most of your string formatting needs. More information on different format symbols is available in the [string formatting part of the standard docs](http://docs.python.org/release/2.5.2/lib/typesseq-strings.html).\n",
"\n",
"It's worth noting that more complicated string formatting methods are in development, but I prefer this system due to its simplicity and its similarity to C formatting strings.\n",
"\n",
"Recall we discussed multiline strings. We can put format characters in these as well, and fill them with the percent sign as before."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"form_letter = \"\"\"\\\n",
"\n",
" %s\n",
"\n",
"Dear %s,\n",
"\n",
"We regret to inform you that your product did not\n",
"ship today due to %s.\n",
"\n",
"We hope to remedy this as soon as possible.\n",
"\n",
" From,\n",
" Your Supplier\n",
"\"\"\"\n",
"\n",
"print(form_letter % (\"July 1, 2013\",\"Valued Customer Bob\",\"alien attack\"))"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"\n",
" July 1, 2013\n",
"\n",
"Dear Valued Customer Bob,\n",
"\n",
"We regret to inform you that your product did not\n",
"ship today due to alien attack.\n",
"\n",
"We hope to remedy this as soon as possible.\n",
"\n",
" From,\n",
" Your Supplier\n",
"\n"
]
}
],
"prompt_number": 156
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The problem with a long block of text like this is that it's often hard to keep track of what all of the variables are supposed to stand for. There's an alternate format where you can pass a dictionary into the formatted string, and give a little bit more information to the formatted string itself. This method looks like:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"form_letter = \"\"\"\\\n",
"\n",
" %(date)s\n",
"\n",
"Dear %(customer)s,\n",
"\n",
"We regret to inform you that your product did not\n",
"ship today due to %(lame_excuse)s.\n",
"\n",
"We hope to remedy this as soon as possible.\n",
"\n",
" From,\n",
" Your Supplier\n",
"\"\"\"\n",
"\n",
"print(form_letter % {\"date\" : \"July 1, 2013\",\"customer\":\"Valued Customer Bob\",\"lame_excuse\":\"alien attack\"})"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"\n",
" July 1, 2013\n",
"\n",
"Dear Valued Customer Bob,\n",
"\n",
"We regret to inform you that your product did not\n",
"ship today due to alien attack.\n",
"\n",
"We hope to remedy this as soon as possible.\n",
"\n",
" From,\n",
" Your Supplier\n",
"\n"
]
}
],
"prompt_number": 157
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"By providing a little bit more information, you're less likely to make mistakes, like referring to your customer as \"alien attack\".\n",
"\n",
"As a scientist, you're less likely to be sending bulk mailings to a bunch of customers. But these are great methods for generating and submitting lots of similar runs, say scanning a bunch of different structures to find the optimal configuration for something.\n",
"\n",
"For example, you can use the following template for NWChem input files:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"nwchem_format = \"\"\"\n",
"start %(jobname)s\n",
"\n",
"title \"%(thetitle)s\"\n",
"charge %(charge)d\n",
"\n",
"geometry units angstroms print xyz autosym\n",
"%(geometry)s\n",
"end\n",
"\n",
"basis\n",
" * library 6-31G**\n",
"end\n",
"\n",
"dft\n",
" xc %(dft_functional)s\n",
" mult %(multiplicity)d\n",
"end\n",
"\n",
"task dft %(jobtype)s\n",
"\"\"\""
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 158
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"If you want to submit a sequence of runs to a computer somewhere, it's pretty easy to put together a little script, maybe even with some more string formatting in it:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"oxygen_xy_coords = [(0,0),(0,0.1),(0.1,0),(0.1,0.1)]\n",
"charge = 0\n",
"multiplicity = 1\n",
"dft_functional = \"b3lyp\"\n",
"jobtype = \"optimize\"\n",
"\n",
"geometry_template = \"\"\"\\\n",
" O %f %f 0.0\n",
" H 0.0 1.0 0.0\n",
" H 1.0 0.0 0.0\"\"\"\n",
"\n",
"for i,xy in enumerate(oxygen_xy_coords):\n",
" thetitle = \"Water run #%d\" % i\n",
" jobname = \"h2o-%d\" % i\n",
" geometry = geometry_template % xy\n",
" print(\"---------\")\n",
" print(nwchem_format % dict(thetitle=thetitle,charge=charge,jobname=jobname,jobtype=jobtype,\n",
" geometry=geometry,dft_functional=dft_functional,multiplicity=multiplicity))"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"---------\n",
"\n",
"start h2o-0\n",
"\n",
"title \"Water run #0\"\n",
"charge 0\n",
"\n",
"geometry units angstroms print xyz autosym\n",
" O 0.000000 0.000000 0.0\n",
" H 0.0 1.0 0.0\n",
" H 1.0 0.0 0.0\n",
"end\n",
"\n",
"basis\n",
" * library 6-31G**\n",
"end\n",
"\n",
"dft\n",
" xc b3lyp\n",
" mult 1\n",
"end\n",
"\n",
"task dft optimize\n",
"\n",
"---------\n",
"\n",
"start h2o-1\n",
"\n",
"title \"Water run #1\"\n",
"charge 0\n",
"\n",
"geometry units angstroms print xyz autosym\n",
" O 0.000000 0.100000 0.0\n",
" H 0.0 1.0 0.0\n",
" H 1.0 0.0 0.0\n",
"end\n",
"\n",
"basis\n",
" * library 6-31G**\n",
"end\n",
"\n",
"dft\n",
" xc b3lyp\n",
" mult 1\n",
"end\n",
"\n",
"task dft optimize\n",
"\n",
"---------\n",
"\n",
"start h2o-2\n",
"\n",
"title \"Water run #2\"\n",
"charge 0\n",
"\n",
"geometry units angstroms print xyz autosym\n",
" O 0.100000 0.000000 0.0\n",
" H 0.0 1.0 0.0\n",
" H 1.0 0.0 0.0\n",
"end\n",
"\n",
"basis\n",
" * library 6-31G**\n",
"end\n",
"\n",
"dft\n",
" xc b3lyp\n",
" mult 1\n",
"end\n",
"\n",
"task dft optimize\n",
"\n",
"---------\n",
"\n",
"start h2o-3\n",
"\n",
"title \"Water run #3\"\n",
"charge 0\n",
"\n",
"geometry units angstroms print xyz autosym\n",
" O 0.100000 0.100000 0.0\n",
" H 0.0 1.0 0.0\n",
" H 1.0 0.0 0.0\n",
"end\n",
"\n",
"basis\n",
" * library 6-31G**\n",
"end\n",
"\n",
"dft\n",
" xc b3lyp\n",
" mult 1\n",
"end\n",
"\n",
"task dft optimize\n",
"\n"
]
}
],
"prompt_number": 159
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This is a very bad geometry for a water molecule, and it would be silly to run so many geometry optimizations of structures that are guaranteed to converge to the same single geometry, but you get the idea of how you can run vast numbers of simulations with a technique like this.\n",
"\n",
"We used the **enumerate** function to loop over both the indices and the items of a sequence, which is valuable when you want a clean way of getting both. **enumerate** is roughly equivalent to:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def my_enumerate(seq):\n",
" l = []\n",
" for i in range(len(seq)):\n",
" l.append((i,seq[i]))\n",
" return l\n",
"my_enumerate(oxygen_xy_coords)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 160,
"text": [
"[(0, (0, 0)), (1, (0, 0.1)), (2, (0.1, 0)), (3, (0.1, 0.1))]"
]
}
],
"prompt_number": 160
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Although enumerate uses **generators** (see below) so that it doesn't have to create a big list, which makes it faster for really long sequenes."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Optional arguments\n",
"You will recall that the **linspace** function can take either two arguments (for the starting and ending points):"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"linspace(0,1)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 161,
"text": [
"array([ 0. , 0.02040816, 0.04081633, 0.06122449, 0.08163265,\n",
" 0.10204082, 0.12244898, 0.14285714, 0.16326531, 0.18367347,\n",
" 0.20408163, 0.2244898 , 0.24489796, 0.26530612, 0.28571429,\n",
" 0.30612245, 0.32653061, 0.34693878, 0.36734694, 0.3877551 ,\n",
" 0.40816327, 0.42857143, 0.44897959, 0.46938776, 0.48979592,\n",
" 0.51020408, 0.53061224, 0.55102041, 0.57142857, 0.59183673,\n",
" 0.6122449 , 0.63265306, 0.65306122, 0.67346939, 0.69387755,\n",
" 0.71428571, 0.73469388, 0.75510204, 0.7755102 , 0.79591837,\n",
" 0.81632653, 0.83673469, 0.85714286, 0.87755102, 0.89795918,\n",
" 0.91836735, 0.93877551, 0.95918367, 0.97959184, 1. ])"
]
}
],
"prompt_number": 161
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"or it can take three arguments, for the starting point, the ending point, and the number of points:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"linspace(0,1,5)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 162,
"text": [
"array([ 0. , 0.25, 0.5 , 0.75, 1. ])"
]
}
],
"prompt_number": 162
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"You can also pass in keywords to exclude the endpoint:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"linspace(0,1,5,endpoint=False)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 163,
"text": [
"array([ 0. , 0.2, 0.4, 0.6, 0.8])"
]
}
],
"prompt_number": 163
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Right now, we only know how to specify functions that have a fixed number of arguments. We'll learn how to do the more general cases here.\n",
"\n",
"If we're defining a simple version of linspace, we would start with:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def my_linspace(start,end):\n",
" npoints = 50\n",
" v = []\n",
" d = (end-start)/float(npoints-1)\n",
" for i in range(npoints):\n",
" v.append(start + i*d)\n",
" return v\n",
"my_linspace(0,1)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 164,
"text": [
"[0.0,\n",
" 0.02040816326530612,\n",
" 0.04081632653061224,\n",
" 0.061224489795918366,\n",
" 0.08163265306122448,\n",
" 0.1020408163265306,\n",
" 0.12244897959183673,\n",
" 0.14285714285714285,\n",
" 0.16326530612244897,\n",
" 0.18367346938775508,\n",
" 0.2040816326530612,\n",
" 0.22448979591836732,\n",
" 0.24489795918367346,\n",
" 0.26530612244897955,\n",
" 0.2857142857142857,\n",
" 0.3061224489795918,\n",
" 0.32653061224489793,\n",
" 0.3469387755102041,\n",
" 0.36734693877551017,\n",
" 0.3877551020408163,\n",
" 0.4081632653061224,\n",
" 0.42857142857142855,\n",
" 0.44897959183673464,\n",
" 0.4693877551020408,\n",
" 0.4897959183673469,\n",
" 0.5102040816326531,\n",
" 0.5306122448979591,\n",
" 0.5510204081632653,\n",
" 0.5714285714285714,\n",
" 0.5918367346938775,\n",
" 0.6122448979591836,\n",
" 0.6326530612244897,\n",
" 0.6530612244897959,\n",
" 0.673469387755102,\n",
" 0.6938775510204082,\n",
" 0.7142857142857142,\n",
" 0.7346938775510203,\n",
" 0.7551020408163265,\n",
" 0.7755102040816326,\n",
" 0.7959183673469387,\n",
" 0.8163265306122448,\n",
" 0.836734693877551,\n",
" 0.8571428571428571,\n",
" 0.8775510204081632,\n",
" 0.8979591836734693,\n",
" 0.9183673469387754,\n",
" 0.9387755102040816,\n",
" 0.9591836734693877,\n",
" 0.9795918367346939,\n",
" 0.9999999999999999]"
]
}
],
"prompt_number": 164
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We can add an optional argument by specifying a default value in the argument list:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def my_linspace(start,end,npoints = 50):\n",
" v = []\n",
" d = (end-start)/float(npoints-1)\n",
" for i in range(npoints):\n",
" v.append(start + i*d)\n",
" return v"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 165
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This gives exactly the same result if we don't specify anything:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"my_linspace(0,1)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 166,
"text": [
"[0.0,\n",
" 0.02040816326530612,\n",
" 0.04081632653061224,\n",
" 0.061224489795918366,\n",
" 0.08163265306122448,\n",
" 0.1020408163265306,\n",
" 0.12244897959183673,\n",
" 0.14285714285714285,\n",
" 0.16326530612244897,\n",
" 0.18367346938775508,\n",
" 0.2040816326530612,\n",
" 0.22448979591836732,\n",
" 0.24489795918367346,\n",
" 0.26530612244897955,\n",
" 0.2857142857142857,\n",
" 0.3061224489795918,\n",
" 0.32653061224489793,\n",
" 0.3469387755102041,\n",
" 0.36734693877551017,\n",
" 0.3877551020408163,\n",
" 0.4081632653061224,\n",
" 0.42857142857142855,\n",
" 0.44897959183673464,\n",
" 0.4693877551020408,\n",
" 0.4897959183673469,\n",
" 0.5102040816326531,\n",
" 0.5306122448979591,\n",
" 0.5510204081632653,\n",
" 0.5714285714285714,\n",
" 0.5918367346938775,\n",
" 0.6122448979591836,\n",
" 0.6326530612244897,\n",
" 0.6530612244897959,\n",
" 0.673469387755102,\n",
" 0.6938775510204082,\n",
" 0.7142857142857142,\n",
" 0.7346938775510203,\n",
" 0.7551020408163265,\n",
" 0.7755102040816326,\n",
" 0.7959183673469387,\n",
" 0.8163265306122448,\n",
" 0.836734693877551,\n",
" 0.8571428571428571,\n",
" 0.8775510204081632,\n",
" 0.8979591836734693,\n",
" 0.9183673469387754,\n",
" 0.9387755102040816,\n",
" 0.9591836734693877,\n",
" 0.9795918367346939,\n",
" 0.9999999999999999]"
]
}
],
"prompt_number": 166
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"But also let's us override the default value with a third argument:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"my_linspace(0,1,5)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 167,
"text": [
"[0.0, 0.25, 0.5, 0.75, 1.0]"
]
}
],
"prompt_number": 167
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We can add arbitrary keyword arguments to the function definition by putting a keyword argument \\*\\*kwargs handle in:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def my_linspace(start,end,npoints=50,**kwargs):\n",
" endpoint = kwargs.get('endpoint',True)\n",
" v = []\n",
" if endpoint:\n",
" d = (end-start)/float(npoints-1)\n",
" else:\n",
" d = (end-start)/float(npoints)\n",
" for i in range(npoints):\n",
" v.append(start + i*d)\n",
" return v\n",
"my_linspace(0,1,5,endpoint=False)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 168,
"text": [
"[0.0, 0.2, 0.4, 0.6000000000000001, 0.8]"
]
}
],
"prompt_number": 168
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"What the keyword argument construction does is to take any additional keyword arguments (i.e. arguments specified by name, like \"endpoint=False\"), and stick them into a dictionary called \"kwargs\" (you can call it anything you like, but it has to be preceded by two stars). You can then grab items out of the dictionary using the **get** command, which also lets you specify a default value. I realize it takes a little getting used to, but it is a common construction in Python code, and you should be able to recognize it.\n",
"\n",
"There's an analogous \\*args that dumps any additional arguments into a list called \"args\". Think about the **range** function: it can take one (the endpoint), two (starting and ending points), or three (starting, ending, and step) arguments. How would we define this?"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def my_range(*args):\n",
" start = 0\n",
" step = 1\n",
" if len(args) == 1:\n",
" end = args[0]\n",
" elif len(args) == 2:\n",
" start,end = args\n",
" elif len(args) == 3:\n",
" start,end,step = args\n",
" else:\n",
" raise Exception(\"Unable to parse arguments\")\n",
" v = []\n",
" value = start\n",
" while True:\n",
" v.append(value)\n",
" value += step\n",
" if value > end: break\n",
" return v"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 169
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Note that we have defined a few new things you haven't seen before: a **break** statement, that allows us to exit a for loop if some conditions are met, and an exception statement, that causes the interpreter to exit with an error message. For example:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"my_range()"
],
"language": "python",
"metadata": {},
"outputs": [
{
"ename": "Exception",
"evalue": "Unable to parse arguments",
"output_type": "pyerr",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[0;31mException\u001b[0m Traceback (most recent call last)",
"\u001b[0;32m<ipython-input-170-0e8004dab150>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mmy_range\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<ipython-input-169-c34e09da2551>\u001b[0m in \u001b[0;36mmy_range\u001b[0;34m(*args)\u001b[0m\n\u001b[1;32m 9\u001b[0m \u001b[0mstart\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0mend\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0mstep\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0margs\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 10\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 11\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mException\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Unable to parse arguments\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 12\u001b[0m \u001b[0mv\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 13\u001b[0m \u001b[0mvalue\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mstart\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;31mException\u001b[0m: Unable to parse arguments"
]
}
],
"prompt_number": 170
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## List Comprehensions and Generators\n",
"List comprehensions are a streamlined way to make lists. They look something like a list definition, with some logic thrown in. For example:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"evens1 = [2*i for i in range(10)]\n",
"print(evens1)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]\n"
]
}
],
"prompt_number": 171
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"You can also put some boolean testing into the construct:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"odds = [i for i in range(20) if i%2==1]\n",
"odds"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 172,
"text": [
"[1, 3, 5, 7, 9, 11, 13, 15, 17, 19]"
]
}
],
"prompt_number": 172
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Here i%2 is the remainder when i is divided by 2, so that i%2==1 is true if the number is odd. Even though this is a relative new addition to the language, it is now fairly common since it's so convenient."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**iterators** are a way of making virtual sequence objects. Consider if we had the nested loop structure:\n",
"\n",
" for i in range(1000000):\n",
" for j in range(1000000):\n",
"\n",
"Inside the main loop, we make a list of 1,000,000 integers, just to loop over them one at a time. We don't need any of the additional things that a lists gives us, like slicing or random access, we just need to go through the numbers one at a time. And we're making 1,000,000 of them. \n",
"\n",
"**iterators** are a way around this. For example, the **xrange** function is the iterator version of range. This simply makes a counter that is looped through in sequence, so that the analogous loop structure would look like:\n",
"\n",
" for i in xrange(1000000):\n",
" for j in xrange(1000000):\n",
"\n",
"Even though we've only added two characters, we've dramatically sped up the code, because we're not making 1,000,000 big lists.\n",
"\n",
"We can define our own iterators using the **yield** statement:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def evens_below(n):\n",
" for i in range(n):\n",
" if i%2 == 0:\n",
" yield i\n",
" return\n",
"\n",
"for i in evens_below(9):\n",
" print(i)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"0\n",
"2\n",
"4\n",
"6\n",
"8\n"
]
}
],
"prompt_number": 173
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We can always turn an iterator into a list using the **list** command:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"list(evens_below(9))"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 174,
"text": [
"[0, 2, 4, 6, 8]"
]
}
],
"prompt_number": 174
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"There's a special syntax called a **generator expression** that looks a lot like a list comprehension:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"evens_gen = (i for i in range(9) if i%2==0)\n",
"for i in evens_gen:\n",
" print(i)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"0\n",
"2\n",
"4\n",
"6\n",
"8\n"
]
}
],
"prompt_number": 175
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Factory Functions\n",
"A factory function is a function that returns a function. They have the fancy name *lexical closure*, which makes you sound really intelligent in front of your CS friends. But, despite the arcane names, factory functions can play a very practical role.\n",
"\n",
"Suppose you want the Gaussian function centered at 0.5, with height 99 and width 1.0. You could write a general function."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def gauss(x,A,a,x0):\n",
" return A*exp(-a*(x-x0)**2)"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 176
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"But what if you need a function with only one argument, like f(x) rather than f(x,y,z,...)? You can do this with Factory Functions:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def gauss_maker(A,a,x0):\n",
" def f(x):\n",
" return A*exp(-a*(x-x0)**2)\n",
" return f"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 177
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"x = linspace(0,1)\n",
"g = gauss_maker(99.0,1.0,0.5)\n",
"plot(x,g(x))"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 178,
"text": [
"[<matplotlib.lines.Line2D at 0x8387810>]"
]
},
{
"output_type": "display_data",
"png": "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\njmVkmFNDJk+GRo2CdXUREZHgOH0aSpSAL7+Em24KsYljS5ZA9uzQsKGNq4uIiARWjhzm0Chfz5q2\n0km3bAmdOkH37sG6soiISHD9+CNUqQJHj4ZQJ719O2zYYIq0iIhIuCpcGFq18u01gl6kX30V+vWD\nbNmCfWUREZHgeuwx374+6MPdefM6bN8ON9wQrKuKiIjYE1I7jq1frwItIiLiCet7d4uIiISzkOqk\nRURExDMq0iIiIi6lIi0iIuJSKtIiIiIupSItIiLiUirSIiIiLqUiLSIi4lIq0iIiIi6lIi0iIuJS\nKtIiIiIupSItIiLiUirSIiIiLqUiLSIi4lIq0iIiIi6lIi0iIuJSKtIiIiIupSItIiLiUirSIiIi\nLqUiLSIi4lIq0iIiIi6lIi0iIuJSXhXpnTt3Ur169fMfefLkYfz48YwYMYKiRYue//WkpCR/5xUP\nJCcn244Q9nSPA0/3ODh0n93NqyJ90003sWHDBjZs2MBXX33FtddeS7t27YiKimLQoEHnf69Fixb+\nzise0Ddd4OkeB57ucXDoPrubz8PdS5cupWzZshQrVgzHcXAcxx+5REREIp7PRfr999+nc+fOAERF\nRTFhwgSqVq1Kr169SEtL8zmgiIhIpIpyfGh9z5w5Q5EiRdi2bRvXX389hw8f5vrrrwdg2LBhHDx4\nkKlTp164WFSU74lFRERCjLelNtqXiy5evJgaNWqcL8yFChU6/3u9e/emdevWF32+hsJFREQ859Nw\n97/+9a/zQ90ABw8ePP/zefPmERcX58vLi4iIRDSvh7tPnjxJiRIl2LNnD7ly5QLg/vvvZ+PGjURF\nRVGqVCneeOMNYmNj/RpYREQkUnjdSefMmZMjR46cL9AA06dPZ/PmzWzatIl+/frRqFEjypUrx4sv\nvnjJ1xgwYADlypWjatWqbNiwwdsoESspKYkKFSpc9h7PnDmTqlWrcvPNN1O/fn02b95sIWVou9o9\n/t26deuIjo5m7ty5QUwXHjy5x8nJyVSvXp0qVaoQHx8f3IBh4mr3+ciRI7Ro0YJq1apRpUoV3nnn\nneCHDGE9e/YkNjb2iiPIXtU8JwDS09OdMmXKOHv27HHOnDnjVK1a1dm2bdtFn/Pxxx87LVu2dBzH\ncVavXu3Url07EFHClif3eOXKlU5aWprjOI6zePFi3eNM8uQe//55jRs3du644w5n9uzZFpKGLk/u\n8dGjR51KlSo5+/fvdxzHcX766ScbUUOaJ/d5+PDhzhNPPOE4jrnH+fPnd86ePWsjbkj64osvnK+/\n/tqpUqXKJX/f25oXkG1B165dS9myZSlZsiQxMTF06tSJBQsWXPQ5CxcupHv37gDUrl2btLQ0UlJS\nAhEnLHlyj+vWrUuePHkAc49/+OEHG1FDlif3GGDChAm0b9/+/ARK8Zwn9/i9997jnnvuoWjRogAU\nLFjQRtSQ5sl9vvHGGzl27BgAx44do0CBAkRH+zS3OKI0aNCAfPnyXfb3va15ASnSBw4coFixYuf/\nu2jRohw4cOCqn6Mi4jlP7vEfTZ06lVatWgUjWtjw9O/xggULeOihhwAtM8wsT+7xrl27SE1NpXHj\nxtSsWZMZM2YEO2bI8+Q+9+nTh61bt1K4cGGqVq3K+PHjgx0zrHlb8wLyNsnTf6icP81Z0z9wnsvM\nvfr888+ZNm0aK1asCGCi8OPJPR44cCCjR48mKipKO+55wZN7fPbsWb7++ms+/fRTTp06Rd26dalT\npw7lypULQsLw4Ml9fuGFF6hWrRrJycns3r2bhIQENm3adNG8I/GNNzUvIEW6SJEi7N+///x/79+/\n//xQ1eU+54cffqBIkSKBiBOWPLnHAJs3b6ZPnz4kJSVdcShG/sqTe/zVV1/RqVMnwEy8Wbx4MTEx\nMbRp0yaoWUOVJ/e4WLFiFCxYkBw5cpAjRw4aNmzIpk2bVKQzwZP7vHLlSp566ikAypQpQ6lSpdi5\ncyc1a9YMatZw5XXN88sT8z85e/asU7p0aWfPnj3Ob7/9dtWJY6tWrdKkpkzy5B5///33TpkyZZxV\nq1ZZShnaPLnHf/TAAw84c+bMCWLC0OfJPd6+fbvTpEkTJz093Tl58qRTpUoVZ+vWrZYShyZP7vPf\n/vY3Z8SIEY7jOM6hQ4ecIkWKOD///LONuCFrz549Hk0cy0zNC0gnHR0dzWuvvUbz5s05d+4cvXr1\nomLFirzxxhsAPPjgg7Rq1YpFixZRtmxZcubMydtvvx2IKGHLk3s8cuRIjh49ev55aUxMDGvXrrUZ\nO6R4co/FN57c4woVKtCiRQtuvvlmsmTJQp8+fahUqZLl5KHFk/s8dOhQevToQdWqVcnIyGDMmDHk\nz5/fcvLQ0blzZ5YtW8aRI0coVqwYzz77LGfPngV8q3k+7d0tIiIigROQ2d0iIiLiOxVpERERl1KR\nFhERcSkVaREREZdSkRYREXEpFWkRERGXUpEWERFxqf8Hc69T43WKCE8AAAAASUVORK5CYII=\n"
}
],
"prompt_number": 178
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Everything in Python is an object, including functions. This means that functions can be returned by other functions. (They can also be passed into other functions, which is also useful, but a topic for another discussion.) In the **gauss_maker** example, the *g* function that is output \"remembers\" the A, a, x0 values it was constructed with, since they're all stored in the local memory space (this is what the *lexical closure* really refers to) of that function.\n",
"\n",
"Factories are one of the more important of the [Software Design Patterns](http://en.wikipedia.org/wiki/Software_design_pattern), which are a set of guidelines to follow to make high-quality, portable, readable, stable software. It's beyond the scope of the current work to go more into either factories or design patterns, but I thought I would mention them for people interested in software design."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Serialization: Save it for later\n",
"*Serialization* refers to the process of outputting data (and occasionally functions) to a database or a regular file, for the purpose of using it later on. In the very early days of programming languages, this was normally done in regular text files. Python is excellent at text processing, and you probably already know enough to get started with this.\n",
"\n",
"When accessing large amounts of data became important, people developed database software based around the Structured Query Language (SQL) standard. I'm not going to cover SQL here, but, if you're interested, I recommend using the [sqlite3](http://docs.python.org/2/library/sqlite3.html) module in the Python standard library.\n",
"\n",
"As data interchange became important, the eXtensible Markup Language (XML) has emerged. XML makes data formats that are easy to write parsers for, greatly simplifying the ambiguity that sometimes arises in the process. Again, I'm not going to cover XML here, but if you're interested in learning more, look into [Element Trees](http://docs.python.org/2/library/xml.etree.elementtree.html), now part of the Python standard library.\n",
"\n",
"Python has a very general serialization format called **pickle** that can turn any Python object, even a function or a class, into a representation that can be written to a
Display the source blob
Display the rendered blob
Raw
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment