{
"metadata": {
"name": "",
"signature": "sha256:d3cbe07a3ab863ac3cf1fcf2ad77869e682309aa40fd2f33747dafc40f18ede2"
},
"nbformat": 3,
"nbformat_minor": 0,
"worksheets": [
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This notebook was put together by [Jake Vanderplas](http://www.vanderplas.com) for UW's [Astro 599](http://www.astro.washington.edu/users/vanderplas/Astr599_2014/) course. Source and license info is on [GitHub](https://github.com/jakevdp/2014_fall_ASTR599/)."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"%run talktools.py"
],
"language": "python",
"metadata": {},
"outputs": [
{
"html": [
""
],
"metadata": {},
"output_type": "display_data",
"text": [
""
]
}
],
"prompt_number": 2
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"# Advanced Python\n",
"## Mishmash:\n",
"## Classes, Exceptions, Iterators, and Generators \n",
"\n",
"We have spent much of our time so far taking a look at scientific tools in Python. But a big part of using Python is an in-depth knowledge of the language itself. The topics here may not have *direct* science applications, but you'd be surprised when and where they can pop up as you use and write scientific Python code.\n",
"\n",
"We'll dive a bit deeper into a few of these topics here."
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"## Advanced Python: Outline\n",
"\n",
"Here is what we plan to cover in this section:\n",
"\n",
"- Classes: defining your own objects\n",
"- Exceptions: handling the unexpected\n",
"- Iterators: sequences on-the-fly\n",
"- Generator Expressions: the sky's the limit"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"## Classes\n",
"\n",
"Python can be used as an *object-oriented* language. An object is an entity that encapsulates *data*, called attributes, and *functionality*, called methods.\n",
"\n",
"Everything in Python is an object. Take for example the ``complex`` object:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"z = 1 + 2j"
],
"language": "python",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [],
"prompt_number": 3
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"# The type function allows us to inspect the object type\n",
"type(z)"
],
"language": "python",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 4,
"text": [
"complex"
]
}
],
"prompt_number": 4
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"# \"calling\" an object type is akin to constructing an object\n",
"z = complex(1, 2)"
],
"language": "python",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [],
"prompt_number": 5
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"# z has real and imaginary attributes\n",
"print(z.real)\n",
"print(z.imag)"
],
"language": "python",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"1.0\n",
"2.0\n"
]
}
],
"prompt_number": 7
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"# z has methods to operate on these attributes\n",
"z.conjugate()"
],
"language": "python",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 9,
"text": [
"(1-2j)"
]
}
],
"prompt_number": 9
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"source": [
"Every data container you see in Python is an object, from integers and floats to lists to numpy arrays."
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"### Classes: creating your own objects\n",
"\n",
"Here we'll show a quick example of spinning our own ``complex``-like object, using a ``class``.\n",
"\n",
"Class definitions look like this:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"class MyClass(object):\n",
" # attributes and methods are defined here\n",
" pass"
],
"language": "python",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [],
"prompt_number": 10
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"# create a MyClass \"instance\" named m\n",
"m = MyClass()\n",
"type(m)"
],
"language": "python",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 12,
"text": [
"__main__.MyClass"
]
}
],
"prompt_number": 12
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"#### Class Initialization\n",
"\n",
"Things get a bit more interesting when we define the ``__init__`` method:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"class MyClass(object):\n",
" def __init__(self):\n",
" print(self)\n",
" print(\"initialization called\")\n",
" pass\n",
" \n",
"m = MyClass()"
],
"language": "python",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"<__main__.MyClass object at 0x10370fc90>\n",
"initialization called\n"
]
}
],
"prompt_number": 14
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"m"
],
"language": "python",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 15,
"text": [
"<__main__.MyClass at 0x10370fc90>"
]
}
],
"prompt_number": 15
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"source": [
"The first argument of ``__init__()`` points to the object itself, and is usually called ``self`` by convention.\n",
"\n",
"Note above that when we print ``self`` and when we print ``m``, we see that they point to the same thing. ``self`` *is* ``m``"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"#### A more interesting initialization\n",
"\n",
"We can use the ``__init__()`` method to accept initialization keyword arguments. Here we'll allow the user to pass a value to the initialization, which is saved in the class:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"class MyClass(object):\n",
" def __init__(self, value):\n",
" self.value = value"
],
"language": "python",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [],
"prompt_number": 16
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"m = MyClass(5.0) # note: the self argument is always implied\n",
"\n",
"m.value"
],
"language": "python",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 17,
"text": [
"5.0"
]
}
],
"prompt_number": 17
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"#### Adding some methods\n",
"\n",
"Now let's add a ``squared()`` method, which returns the square of the value:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"class MyClass(object):\n",
" def __init__(self, value):\n",
" self.value = value\n",
" \n",
" def squared(self):\n",
" return self.value ** 2"
],
"language": "python",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [],
"prompt_number": 18
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"m = MyClass(5)\n",
"m.squared()"
],
"language": "python",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 19,
"text": [
"25"
]
}
],
"prompt_number": 19
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"source": [
"Methods act just like functions: they can have any number of arguments or keyword arguments, they can accept ``*args`` and ``**kwargs`` arguments, and can call other methods or functions."
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"#### Other special methods\n",
"\n",
"There are numerous special methods, indicated by double underscores. One important one is the ``__repr__`` method, which controls how an instance of the class is represented when it is output:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"class MyClass(object):\n",
" def __init__(self, value):\n",
" self.value = value\n",
" \n",
" def squared(self):\n",
" return self.value ** 2\n",
" \n",
" def __repr__(self):\n",
" return \"MyClass(value=\" + str(self.value) + \")\""
],
"language": "python",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [],
"prompt_number": 20
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"m = MyClass(10)\n",
"print(m)\n",
"print(type(m))"
],
"language": "python",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"MyClass(value=10)\n",
"\n"
]
}
],
"prompt_number": 21
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"#### Other special methods\n",
"\n",
"Other special methods to be aware of:\n",
"\n",
"- String representations: ``__str__``, ``__repr__``, ``__hash__``, etc.\n",
"- Arithmetic: ``__add__``, ``__sub__``, ``__mul__``, ``__div__``, etc.\n",
"- Item access: ``__getitem__``, ``__setitem__``, etc.\n",
"- Attribute Access: ``__getattr__``, ``__setattr__``, etc.\n",
"- Comparison: ``__eq__``, ``__lt__``, ``__gt__``, etc.\n",
"- Constructors/Destructors: ``__new__``, ``__init__``, ``__del__``, etc.\n",
"- Type Conversion: ``__int__``, ``__long__``, ``__float__``, etc.\n",
"\n",
"For a nice discussion and explanation of these and many other special double-underscore methods, see [http://www.rafekettler.com/magicmethods.html](http://www.rafekettler.com/magicmethods.html)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"## Exercise: A Custom Complex Object\n",
"\n",
"Create a class ``MyComplex`` which behaves like the built-in complex numbers. You should be able to execute the following code and see these results:\n",
"\n",
" >>> z = MyComplex(2, 3)\n",
" >>> print z\n",
" (2, 3j)\n",
" >>> print z.real\n",
" 2\n",
" >>> print z.imag\n",
" 3\n",
" >>> print z.conjugate()\n",
" (2, -3j)\n",
" >>> print type(z.conjugate())\n",
" \n",
" \n",
"Note that the ``conjugate()`` method should return *a new object of type MyComplex*."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [],
"language": "python",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [],
"prompt_number": 21
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"source": [
"If you finish this quickly, search online for help on defining the ``__add__`` method such that you can compute:\n",
"\n",
" >>> z + z.conjugate()\n",
" (4, 0j)"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [],
"language": "python",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [],
"prompt_number": 21
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"## Exceptions\n",
"### Handling the Unexpected\n",
"\n",
"Sometimes things go wrong in your code, and this is where exceptions come in. For example, you may have illegal inputs to an operation:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"0/0"
],
"language": "python",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"ename": "ZeroDivisionError",
"evalue": "division by zero",
"output_type": "pyerr",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[0;31mZeroDivisionError\u001b[0m Traceback (most recent call last)",
"\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0;36m0\u001b[0m\u001b[0;34m/\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
"\u001b[0;31mZeroDivisionError\u001b[0m: division by zero"
]
}
],
"prompt_number": 22
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"source": [
"Or you may call a function with the wrong number of arguments:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"from math import sqrt\n",
"sqrt(2, 3)"
],
"language": "python",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"ename": "TypeError",
"evalue": "sqrt() takes exactly one argument (2 given)",
"output_type": "pyerr",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)",
"\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0mmath\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0msqrt\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0msqrt\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m2\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m3\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
"\u001b[0;31mTypeError\u001b[0m: sqrt() takes exactly one argument (2 given)"
]
}
],
"prompt_number": 23
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"source": [
"Or you may choose an index that is out of range:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"L = [4, 5, 6]\n",
"L[100]"
],
"language": "python",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"ename": "IndexError",
"evalue": "list index out of range",
"output_type": "pyerr",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[0;31mIndexError\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[0mL\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;36m4\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m5\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m6\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0mL\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m100\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
"\u001b[0;31mIndexError\u001b[0m: list index out of range"
]
}
],
"prompt_number": 24
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"source": [
"Or a dictionary key that doesn't exist:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"D = {'a':2, 'b':300}\n",
"print D['Q']"
],
"language": "python",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"ename": "SyntaxError",
"evalue": "invalid syntax (, line 2)",
"output_type": "pyerr",
"traceback": [
"\u001b[0;36m File \u001b[0;32m\"\"\u001b[0;36m, line \u001b[0;32m2\u001b[0m\n\u001b[0;31m print D['Q']\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m invalid syntax\n"
]
}
],
"prompt_number": 25
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"source": [
"Or the wrong value for a conversion function:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"x = int('ABC')"
],
"language": "python",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"ename": "ValueError",
"evalue": "invalid literal for int() with base 10: 'ABC'",
"output_type": "pyerr",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[0;31mValueError\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[0mx\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'ABC'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
"\u001b[0;31mValueError\u001b[0m: invalid literal for int() with base 10: 'ABC'"
]
}
],
"prompt_number": 26
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"source": [
"These are known as ``Exceptions``, and handling them appropriately is a big part of writing usable code."
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"### Handling exceptions: ``try...except``\n",
"\n",
"Exceptions can be handled using the ``try`` and ``except`` statements:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def try_division(value):\n",
" try:\n",
" x = value / value\n",
" return x\n",
" except ZeroDivisionError:\n",
" return 'Not A Number'\n",
" \n",
"print(try_division(1))\n",
"print(try_division(0))"
],
"language": "python",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"1.0\n",
"Not A Number\n"
]
}
],
"prompt_number": 28
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def get_an_int():\n",
" while True:\n",
" try:\n",
" # change to raw_input for Python 2\n",
" x = int(input(\"Enter an integer: \"))\n",
" print(\" >> Thank you!\")\n",
" break\n",
" except ValueError:\n",
" print(\" >> Boo. That's not an integer.\")\n",
" return x\n",
"\n",
"get_an_int()"
],
"language": "python",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"stream": "stdout",
"text": [
"Enter an integer: e\n"
]
},
{
"output_type": "stream",
"stream": "stdout",
"text": [
" >> Boo. That's not an integer.\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"stream": "stdout",
"text": [
"Enter an integer: rew\n"
]
},
{
"output_type": "stream",
"stream": "stdout",
"text": [
" >> Boo. That's not an integer.\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"stream": "stdout",
"text": [
"Enter an integer: 3.4\n"
]
},
{
"output_type": "stream",
"stream": "stdout",
"text": [
" >> Boo. That's not an integer.\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"stream": "stdout",
"text": [
"Enter an integer: 4\n"
]
},
{
"output_type": "stream",
"stream": "stdout",
"text": [
" >> Thank you!\n"
]
},
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 31,
"text": [
"4"
]
}
],
"prompt_number": 31
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"### Advanced Exception Handling\n",
"\n",
"Other things to be aware of:\n",
"\n",
"- you may use multiple ``except`` statements for different exception types\n",
"- ``else`` and ``finally`` statements can fine-tune the exception handling\n",
"\n",
"More information is available in the [Python documentation](http://docs.python.org/2/tutorial/errors.html) and in the [scipy lectures](http://scipy-lectures.github.io/intro/language/exceptions.html)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"### Raising your own exceptions\n",
"\n",
"In addition to handling exceptions, you can also raise your own exceptions using the ``raise`` keyword:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def laugh(N):\n",
" if N < 0:\n",
" raise ValueError(\"N must be positive\")\n",
" return N * \"ha! \""
],
"language": "python",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [],
"prompt_number": 32
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"laugh(10)"
],
"language": "python",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 33,
"text": [
"'ha! ha! ha! ha! ha! ha! ha! ha! ha! ha! '"
]
}
],
"prompt_number": 33
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"laugh(-4)"
],
"language": "python",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"ename": "ValueError",
"evalue": "N must be positive",
"output_type": "pyerr",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[0;31mValueError\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[0mlaugh\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m-\u001b[0m\u001b[0;36m4\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;36mlaugh\u001b[0;34m(N)\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mlaugh\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mN\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mN\u001b[0m \u001b[0;34m<\u001b[0m \u001b[0;36m0\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 3\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mValueError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"N must be positive\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 4\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mN\u001b[0m \u001b[0;34m*\u001b[0m \u001b[0;34m\"ha! \"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;31mValueError\u001b[0m: N must be positive"
]
}
],
"prompt_number": 34
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"### Custom Exceptions\n",
"\n",
"For your own projects, you may desire to define custom exception types, which is done through **class inheritance**.\n",
"\n",
"The important point to note here is that *exceptions themselves are classes*:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"v = ValueError(\"message\")\n",
"type(v)"
],
"language": "python",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 36,
"text": [
"ValueError"
]
}
],
"prompt_number": 36
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"source": [
"When you ``raise`` an exception, you are creating an **instance** of the exception type, and passing it to the ``raise`` keyword:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"raise ValueError(\"error message\")"
],
"language": "python",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"ename": "ValueError",
"evalue": "error message",
"output_type": "pyerr",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[0;31mValueError\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;32mraise\u001b[0m \u001b[0mValueError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"error message\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
"\u001b[0;31mValueError\u001b[0m: error message"
]
}
],
"prompt_number": 37
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"source": [
"In the seminar later this quarter we'll dive into **object-oriented programming**, but here's a quick preview of the principle of **inheritance**: new objects derived from existing objects:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"# define a custom exception, inheriting from the base class Exception\n",
"class CustomException(Exception):\n",
" # can define custom behavior here\n",
" pass\n",
"\n",
"raise CustomException(\"error message\")"
],
"language": "python",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"ename": "CustomException",
"evalue": "error message",
"output_type": "pyerr",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[0;31mCustomException\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[0;32mpass\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 6\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mCustomException\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"error message\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
"\u001b[0;31mCustomException\u001b[0m: error message"
]
}
],
"prompt_number": 38
},
{
"cell_type": "code",
"collapsed": false,
"input": [],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 29
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"## Iterators\n",
"Iterators are a high-level concept in Python that allow a sequence of objects to be examined in sequence.\n",
"\n",
"We've seen a basic example of this in the for-loop:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"for i in range(10):\n",
" print(i)"
],
"language": "python",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"0\n",
"1\n",
"2\n",
"3\n",
"4\n",
"5\n",
"6\n",
"7\n",
"8\n",
"9\n"
]
}
],
"prompt_number": 40
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"In Python 3.x, ``range`` does not actually construct a list of numbers, but just an object which acts like a list (in Python 2.x, ``range`` does actually create a list)"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"range(10)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 41,
"text": [
"range(0, 10)"
]
}
],
"prompt_number": 41
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"list(range(10))"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 42,
"text": [
"[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]"
]
}
],
"prompt_number": 42
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"import sys\n",
"print(sys.getsizeof(list(range(1000))))\n",
"print(sys.getsizeof(range(1000)))"
],
"language": "python",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"9120\n",
"48\n"
]
}
],
"prompt_number": 44
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"### Handy Iterators to know about"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"D = {'a':0, 'b':1, 'c':2}\n",
"\n",
"D.keys()"
],
"language": "python",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 47,
"text": [
"dict_keys(['a', 'b', 'c'])"
]
}
],
"prompt_number": 47
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"D.values()"
],
"language": "python",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 48,
"text": [
"dict_values([0, 1, 2])"
]
}
],
"prompt_number": 48
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"D.items()"
],
"language": "python",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 49,
"text": [
"dict_items([('a', 0), ('b', 1), ('c', 2)])"
]
}
],
"prompt_number": 49
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"for key in D.keys():\n",
" print(key)"
],
"language": "python",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"a\n",
"b\n",
"c\n"
]
}
],
"prompt_number": 51
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"for key in D:\n",
" print(key)"
],
"language": "python",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"a\n",
"b\n",
"c\n"
]
}
],
"prompt_number": 52
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"for item in D.items():\n",
" print(item)"
],
"language": "python",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"('a', 0)\n",
"('b', 1)\n",
"('c', 2)\n"
]
}
],
"prompt_number": 55
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"### ``itertools``: more sophisticated iterations"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"import itertools\n",
"dir(itertools)"
],
"language": "python",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 56,
"text": [
"['__doc__',\n",
" '__loader__',\n",
" '__name__',\n",
" '__package__',\n",
" '_grouper',\n",
" '_tee',\n",
" '_tee_dataobject',\n",
" 'accumulate',\n",
" 'chain',\n",
" 'combinations',\n",
" 'combinations_with_replacement',\n",
" 'compress',\n",
" 'count',\n",
" 'cycle',\n",
" 'dropwhile',\n",
" 'filterfalse',\n",
" 'groupby',\n",
" 'islice',\n",
" 'permutations',\n",
" 'product',\n",
" 'repeat',\n",
" 'starmap',\n",
" 'takewhile',\n",
" 'tee',\n",
" 'zip_longest']"
]
}
],
"prompt_number": 56
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"for c in itertools.combinations([1, 2, 3, 4], 2):\n",
" print(c)"
],
"language": "python",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"(1, 2)\n",
"(1, 3)\n",
"(1, 4)\n",
"(2, 3)\n",
"(2, 4)\n",
"(3, 4)\n"
]
}
],
"prompt_number": 57
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"for p in itertools.permutations([1, 2, 3]):\n",
" print(p)"
],
"language": "python",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"(1, 2, 3)\n",
"(1, 3, 2)\n",
"(2, 1, 3)\n",
"(2, 3, 1)\n",
"(3, 1, 2)\n",
"(3, 2, 1)\n"
]
}
],
"prompt_number": 58
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"for val in itertools.chain(range(0, 4), range(-4, 0)):\n",
" print(val, end=' ')"
],
"language": "python",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"0 1 2 3 -4 -3 -2 -1 "
]
}
],
"prompt_number": 59
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"# zip: itertools.izip is an iterator equivalent\n",
"for val in zip([1, 2, 3], ['a', 'b', 'c']):\n",
" print(val)"
],
"language": "python",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"(1, 'a')\n",
"(2, 'b')\n",
"(3, 'c')\n"
]
}
],
"prompt_number": 60
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"### Quick Exercise:\n",
"\n",
"Write a function ``count_pairs(N, m)`` which returns the number of pairs of numbers in the sequence $0 ... N-1$ whose sum is divisible by ``m``.\n",
"\n",
"For example, if ``N = 3`` and ``m = 2``, the pairs are\n",
"\n",
" [(0, 1), (0, 2), (1, 2)]\n",
" \n",
"The sum of each pair respectively is ``[1, 2, 3]``, and there is a single pair whose sum is divisible by 2, so the result is ``1``.\n",
"\n",
"1. What is the result for $(N,m) = (10, 2)$?\n",
"2. What is the result for $(N,m) = (1000, 5)$?"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"### From iterators to generators: the ``yield`` statement\n",
"\n",
"Python provides a ``yield`` statement that allows you to make your own iterators. Technically the result is called a \"generator object\".\n",
"\n",
"For example, here's one way you can create an generator that returns all even numbers in a sequence:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def select_evens(L):\n",
" for value in L:\n",
" if value % 2 == 0:\n",
" yield value"
],
"language": "python",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [],
"prompt_number": 61
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"for val in select_evens([1,2,5,3,6,4]):\n",
" print(val)"
],
"language": "python",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"2\n",
"6\n",
"4\n"
]
}
],
"prompt_number": 63
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"source": [
"The ``yield`` statement is like a ``return`` statement, but the iterator remembers where it is in the execution, and comes back to that point on the next pass."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Breakout: Generator Practice"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Fibonacci Numbers\n",
"\n",
"Here is a loop which prints the first 10 Fibonacci numbers:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"a, b = 0, 1\n",
"for i in range(10):\n",
" print(b)\n",
" a, b = b, a + b"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"1\n",
"1\n",
"2\n",
"3\n",
"5\n",
"8\n",
"13\n",
"21\n",
"34\n",
"55\n"
]
}
],
"prompt_number": 72
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Using a similar strategy, write a generator expression which generates the first $N$ Fibonacci numbers"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def fib(N):\n",
" # your code here"
],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"for num in fib(N):\n",
" print(num)"
],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"### Example: Primes via the Sieve of Eratosthenes\n",
"\n",
"Here is a function which uses the Sieve of Eratosthenes to generate the first $N$ prime numbers. Rewrite this using the ``yield`` statement as a generator over the first $N$ primes:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def list_primes(Nprimes):\n",
" N = 2\n",
" found_primes = []\n",
" while True:\n",
" if all([N % p != 0 for p in found_primes]):\n",
" found_primes.append(N)\n",
" if len(found_primes) >= Nprimes:\n",
" break\n",
" N += 1\n",
" return found_primes\n",
"\n",
"top_primes(10)"
],
"language": "python",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 73,
"text": [
"[2, 3, 5, 7, 11, 13, 17, 19, 23, 29]"
]
}
],
"prompt_number": 73
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def iter_primes(Nprimes):\n",
" # your code here"
],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"# Find the first twenty primes\n",
"for N in iter_primes(20):\n",
" print(N, end=' ')"
],
"language": "python",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 "
]
}
],
"prompt_number": 66
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"## Bonus: Generator Expressions\n",
"\n",
"If you finish the above examples, try wrapping your head around *generator expressions*.\n",
"\n",
"We previously saw examples of **list comprehensions** which can create lists succinctly in one line:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"L = []\n",
"for i in range(20):\n",
" if i % 3 > 0:\n",
" L.append(i)\n",
"L"
],
"language": "python",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 67,
"text": [
"[1, 2, 4, 5, 7, 8, 10, 11, 13, 14, 16, 17, 19]"
]
}
],
"prompt_number": 67
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"# or, as a list comprehension\n",
"[i for i in range(20) if i % 3 > 0]"
],
"language": "python",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 68,
"text": [
"[1, 2, 4, 5, 7, 8, 10, 11, 13, 14, 16, 17, 19]"
]
}
],
"prompt_number": 68
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"source": [
"The corresponding construction of an iterator is known as a \"generator expression\":"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def genfunc():\n",
" for i in range(20):\n",
" if i % 3 > 0:\n",
" yield i\n",
"print(genfunc())\n",
"print(list(genfunc())) # convert iterator to list"
],
"language": "python",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"\n",
"[1, 2, 4, 5, 7, 8, 10, 11, 13, 14, 16, 17, 19]\n"
]
}
],
"prompt_number": 70
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"# or, equivalently, as a \"generator expression\"\n",
"g = (i for i in range(20) if i % 3 > 0)\n",
"print(g)\n",
"print(list(g)) # convert generator expression to list"
],
"language": "python",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
" at 0x104537a00>\n",
"[1, 2, 4, 5, 7, 8, 10, 11, 13, 14, 16, 17, 19]\n"
]
}
],
"prompt_number": 71
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"source": [
"The syntax is identical to that of list comprehensions, except we surround the expression with ``()`` rather than with ``[]``. Again, this may seem a bit specialized, but it allows some extremely powerful constructions in Python, and it's one of the features of Python that some people get very excited about."
]
}
],
"metadata": {}
}
]
}