Last active
December 31, 2015 05:09
-
-
Save anandology/7939444 to your computer and use it in GitHub Desktop.
Advanced Python TrainingDecember 13-14, 2013Global Analytics -- http://nbviewer.ipython.org/gist/anandology/7939444
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"metadata": { | |
"name": "" | |
}, | |
"nbformat": 3, | |
"nbformat_minor": 0, | |
"worksheets": [ | |
{ | |
"cells": [ | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"# Advanced Python Training - Day 2\n", | |
"December 13-14, 2013<br/>\n", | |
"Global Analytics" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"import re\n", | |
"class Person(object):\n", | |
" def __init__(self, firstname, lastname):\n", | |
" self.firstname = firstname\n", | |
" self.lastname = lastname\n", | |
" self._phone = \"00000000\"\n", | |
" \n", | |
" @property\n", | |
" def fullname(self):\n", | |
" return self.firstname + \" \" + self.lastname\n", | |
" \n", | |
" def get_phone(self):\n", | |
" return self._phone\n", | |
" \n", | |
" def set_phone(self, value):\n", | |
" if not re.match(\"^[ 0-9-]+$\", value):\n", | |
" raise ValueError(\"Invalid phone number: %r\"% value)\n", | |
" self._phone = value\n", | |
" \n", | |
" phone = property(get_phone, set_phone)\n", | |
"\n", | |
"p = Person(\"Foo\", \"Bar\")\n", | |
"print p.fullname" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"stream": "stdout", | |
"text": [ | |
"Foo Bar\n" | |
] | |
} | |
], | |
"prompt_number": 16 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"p.phone = \"not-a-number\"" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"ename": "ValueError", | |
"evalue": "Invalid phone number: 'not-a-number'", | |
"output_type": "pyerr", | |
"traceback": [ | |
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", | |
"\u001b[0;32m<ipython-input-17-dca623967e9e>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mphone\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m\"not-a-number\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", | |
"\u001b[0;32m<ipython-input-16-8b87d2913e58>\u001b[0m in \u001b[0;36mphone\u001b[0;34m(self, value)\u001b[0m\n\u001b[1;32m 17\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mphone\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mvalue\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 18\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mre\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mmatch\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"^[ 0-9-]+$\"\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mvalue\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 19\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mValueError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Invalid phone number: %r\"\u001b[0m\u001b[0;34m%\u001b[0m \u001b[0mvalue\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 20\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_phone\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mvalue\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 21\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", | |
"\u001b[0;31mValueError\u001b[0m: Invalid phone number: 'not-a-number'" | |
] | |
} | |
], | |
"prompt_number": 17 | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"**Problem** Add `url` property to the following class. The `url` of a post should be of the form `/yyyy/mm/dd/title-with-spaces-replaced-with-hyphens`\n", | |
"\n", | |
" class Post(object):\n", | |
" def __init__(self, year, month, day, title):\n", | |
" self.year = year\n", | |
" self.month = month\n", | |
" self.day = day\n", | |
" self.title = title\n", | |
" \n", | |
"Example:\n", | |
"\n", | |
" >>> p = Post(2013, 12, 7, \"hello world\")\n", | |
" >>> p.url\n", | |
" '/2013/12/07/hello-world'\n", | |
" >>> p.day = 9\n", | |
" >>> p.url\n", | |
" '/2013/12/09/hello-world'" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"!date" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"stream": "stdout", | |
"text": [ | |
"Sat Dec 14 09:32:11 IST 2013\r\n" | |
] | |
} | |
], | |
"prompt_number": 18 | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"## WSGI" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"%%file hello_wsgi.py\n", | |
"\n", | |
"import wsgiref.simple_server\n", | |
"\n", | |
"def application(environ, start_response):\n", | |
" \"\"\"Simple WSGI application.\n", | |
" \"\"\"\n", | |
" print environ[\"REQUEST_METHOD\"], environ[\"PATH_INFO\"]\n", | |
" start_response(\"200 OK\", [(\"Content-type\", \"text/plain\")])\n", | |
" return [\"hello wsgi\\n\"]\n", | |
" \n", | |
"def run(host, port):\n", | |
" # Creating a server\n", | |
" # The server calls the application function for every request\n", | |
" server = wsgiref.simple_server.make_server(host, port, application)\n", | |
" print \"http://%s:%s/\" % (host, port)\n", | |
" \n", | |
" # go into infinite loop to serve requests\n", | |
" server.serve_forever()\n", | |
" \n", | |
"if __name__ == \"__main__\":\n", | |
" run(\"localhost\", 8080)" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"stream": "stdout", | |
"text": [ | |
"Overwriting hello_wsgi.py\n" | |
] | |
} | |
], | |
"prompt_number": 3 | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"Step1: lets create a Request class.\n", | |
"\n", | |
" class Request(object):\n", | |
" def __init__(self, environ):\n", | |
" self.environ = environ\n", | |
" \n", | |
" @property\n", | |
" def path(self):\n", | |
" return self.environ['PATH_INFO']\n", | |
" \n", | |
" " | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"%%file rajinikanth.py\n", | |
"\"\"\"A new web framework as smart as rajini kanth!\n", | |
"\"\"\"\n", | |
"import wsgiref.simple_server\n", | |
"\n", | |
"class Application(object):\n", | |
" def __init__(self):\n", | |
" self.url_mapping = []\n", | |
" self.after_request_func = None\n", | |
" \n", | |
" def run(self, host=\"0.0.0.0\", port=8080):\n", | |
" print \"run\"\n", | |
" server = wsgiref.simple_server.make_server(host, port, self)\n", | |
" print \"http://%s:%s/\" % (host, port)\n", | |
" server.serve_forever() \n", | |
" \n", | |
" def __call__(self, environ, start_response):\n", | |
" request = Request(environ)\n", | |
" start_response(\"200 OK\", [(\"Content-type\", \"text/plain\")])\n", | |
" \n", | |
" response = None\n", | |
" for path, func in self.url_mapping:\n", | |
" if path == request.path:\n", | |
" response = func(request)\n", | |
" break\n", | |
" \n", | |
" if not response:\n", | |
" response = \"Not Found\"\n", | |
" \n", | |
" if self.after_request_func:\n", | |
" response = self.after_request_func(response)\n", | |
" \n", | |
" return [response]\n", | |
" \n", | |
" def route(self, path):\n", | |
" def decorator(func):\n", | |
" self.url_mapping.append((path, func))\n", | |
" return func\n", | |
" return decorator\n", | |
" \n", | |
" def after_request(self, func):\n", | |
" self.after_request_func = func\n", | |
" return func\n", | |
" \n", | |
"\n", | |
"class Request(object):\n", | |
" def __init__(self, environ):\n", | |
" self.environ = environ\n", | |
" \n", | |
" @property\n", | |
" def path(self):\n", | |
" return self.environ['PATH_INFO']\n", | |
" " | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"stream": "stdout", | |
"text": [ | |
"Overwriting rajinikanth.py\n" | |
] | |
} | |
], | |
"prompt_number": 5 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"%%file hello1.py\n", | |
"\n", | |
"from rajinikanth import Application\n", | |
"\n", | |
"app = Application()\n", | |
"\n", | |
"@app.after_request\n", | |
"def add_header(response):\n", | |
" return \"=======\\n\" + response + \"=========\\n\"\n", | |
"\n", | |
"#@app.route(\"/hello\")\n", | |
"def hello(request):\n", | |
" return \"Hello, world!\\n\"\n", | |
"decor = app.route(\"/hello\")\n", | |
"hello = decor(hello)\n", | |
"\n", | |
"\n", | |
"@app.route(\"/bye\")\n", | |
"def bye(request):\n", | |
" return \"Good bye!\\n\"\n", | |
"\n", | |
"if __name__ == \"__main__\":\n", | |
" app.run(\"localhost\", 7070)" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"stream": "stdout", | |
"text": [ | |
"Overwriting hello1.py\n" | |
] | |
} | |
], | |
"prompt_number": 4 | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"## Old-style vs. new-style classes" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"class Old:\n", | |
" pass\n", | |
"\n", | |
"class New(object):\n", | |
" pass\n", | |
"\n", | |
"old = Old()\n", | |
"new = New()" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [], | |
"prompt_number": 8 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"type(old)" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"metadata": {}, | |
"output_type": "pyout", | |
"prompt_number": 9, | |
"text": [ | |
"instance" | |
] | |
} | |
], | |
"prompt_number": 9 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"type(new)" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"metadata": {}, | |
"output_type": "pyout", | |
"prompt_number": 10, | |
"text": [ | |
"__main__.New" | |
] | |
} | |
], | |
"prompt_number": 10 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"old.__len__ = lambda: 10\n", | |
"new.__len__ = lambda: 10" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [], | |
"prompt_number": 11 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"len(old)" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"metadata": {}, | |
"output_type": "pyout", | |
"prompt_number": 12, | |
"text": [ | |
"10" | |
] | |
} | |
], | |
"prompt_number": 12 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"len(new)" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"ename": "TypeError", | |
"evalue": "object of type 'New' has no len()", | |
"output_type": "pyerr", | |
"traceback": [ | |
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", | |
"\u001b[0;32m<ipython-input-13-12fb657d434e>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mlen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mnew\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", | |
"\u001b[0;31mTypeError\u001b[0m: object of type 'New' has no len()" | |
] | |
} | |
], | |
"prompt_number": 13 | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"**Descriptors**" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"class Person:\n", | |
" @property\n", | |
" def fullname(self):\n", | |
" return \"xxx\"\n", | |
" \n", | |
"p = Person()" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [], | |
"prompt_number": 16 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"print p.fullname" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"stream": "stdout", | |
"text": [ | |
"xxx\n" | |
] | |
} | |
], | |
"prompt_number": 17 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"Person.fullname" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"metadata": {}, | |
"output_type": "pyout", | |
"prompt_number": 18, | |
"text": [ | |
"<property at 0x10360b890>" | |
] | |
} | |
], | |
"prompt_number": 18 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"p.__dict__" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"metadata": {}, | |
"output_type": "pyout", | |
"prompt_number": 19, | |
"text": [ | |
"{}" | |
] | |
} | |
], | |
"prompt_number": 19 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"Person.__dict__" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"metadata": {}, | |
"output_type": "pyout", | |
"prompt_number": 20, | |
"text": [ | |
"{'__doc__': None,\n", | |
" '__module__': '__main__',\n", | |
" 'fullname': <property at 0x10360b890>}" | |
] | |
} | |
], | |
"prompt_number": 20 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"dir(Person.fullname)" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"metadata": {}, | |
"output_type": "pyout", | |
"prompt_number": 21, | |
"text": [ | |
"['__class__',\n", | |
" '__delattr__',\n", | |
" '__delete__',\n", | |
" '__doc__',\n", | |
" '__format__',\n", | |
" '__get__',\n", | |
" '__getattribute__',\n", | |
" '__hash__',\n", | |
" '__init__',\n", | |
" '__new__',\n", | |
" '__reduce__',\n", | |
" '__reduce_ex__',\n", | |
" '__repr__',\n", | |
" '__set__',\n", | |
" '__setattr__',\n", | |
" '__sizeof__',\n", | |
" '__str__',\n", | |
" '__subclasshook__',\n", | |
" 'deleter',\n", | |
" 'fdel',\n", | |
" 'fget',\n", | |
" 'fset',\n", | |
" 'getter',\n", | |
" 'setter']" | |
] | |
} | |
], | |
"prompt_number": 21 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"Person.fullname.__get__(p)" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"metadata": {}, | |
"output_type": "pyout", | |
"prompt_number": 22, | |
"text": [ | |
"'xxx'" | |
] | |
} | |
], | |
"prompt_number": 22 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"class Constant(object):\n", | |
" def __init__(self, value):\n", | |
" self.value = value\n", | |
" \n", | |
" def __get__(self, obj, type=None):\n", | |
" print \"Constant.__get__\"\n", | |
" return self.value\n", | |
" \n", | |
" def __set__(self, obj, value):\n", | |
" raise Exception(\"Can't change a constant\")\n", | |
" \n", | |
"class Math(object):\n", | |
" pi = Constant(3.14)\n", | |
" \n", | |
"m = Math()\n", | |
"print m.pi\n", | |
"print m.pi" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"stream": "stdout", | |
"text": [ | |
"Constant.__get__\n", | |
"3.14\n", | |
"Constant.__get__\n", | |
"3.14\n" | |
] | |
} | |
], | |
"prompt_number": 29 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"m.pi = 3" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"ename": "Exception", | |
"evalue": "Can't change a constant", | |
"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-30-e238ec0b7a72>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mm\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpi\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;36m3\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", | |
"\u001b[0;32m<ipython-input-29-705c8de9ce8d>\u001b[0m in \u001b[0;36m__set__\u001b[0;34m(self, obj, value)\u001b[0m\n\u001b[1;32m 8\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 9\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0m__set__\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mobj\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mvalue\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 10\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mException\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Can't change a constant\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 11\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 12\u001b[0m \u001b[0;32mclass\u001b[0m \u001b[0mMath\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mobject\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", | |
"\u001b[0;31mException\u001b[0m: Can't change a constant" | |
] | |
} | |
], | |
"prompt_number": 30 | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"It is a common pattern to lazily initialize some values and reuse them.\n", | |
"\n", | |
" class Posts(object):\n", | |
" def get_categories(self):\n", | |
" if self.categories is None:\n", | |
" self.categories = self._get_categories_from_db()\n", | |
" return self.categories\n", | |
"\n", | |
"Wouldn't it be nice if we can do it like:\n", | |
"\n", | |
" class Posts(object):\n", | |
" @lazy_property\n", | |
" def categories(self):\n", | |
" # get categories from db\n", | |
" return result\n", | |
" \n", | |
" \n", | |
" class Foo:\n", | |
" @lazy_proeperty\n", | |
" def db(self):\n", | |
" \"\"\"Connects to database and returns the database connection\"\"\"\n", | |
" print \"connecting to database\"\n", | |
" return \"dummy-connection\" # returning a dummy connection" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"A small clarification about decorators.\n", | |
"\n" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"def foo(a):\n", | |
" return 1\n", | |
"\n", | |
"@foo\n", | |
"def square(x):\n", | |
" return x*x\n", | |
"\n", | |
"print square" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"stream": "stdout", | |
"text": [ | |
"1\n" | |
] | |
} | |
], | |
"prompt_number": 33 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"class Foo:\n", | |
" def __init__(self, x):\n", | |
" self.x = x\n", | |
" \n", | |
"@Foo\n", | |
"def square(x):\n", | |
" return x*x\n", | |
"\n", | |
"print square" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"stream": "stdout", | |
"text": [ | |
"<__main__.Foo instance at 0x103624b48>\n" | |
] | |
} | |
], | |
"prompt_number": 34 | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"Lets look at implementation of `property` descriptor." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"class my_property(object):\n", | |
" def __init__(self, getter):\n", | |
" print \"myproperty.__init__\", getter\n", | |
" self.getter = getter\n", | |
" \n", | |
" def __get__(self, obj, type):\n", | |
" if obj is None:\n", | |
" return self\n", | |
" print \"__get__\", obj, type\n", | |
" return self.getter(obj)\n", | |
" \n", | |
"class Person(object):\n", | |
" @my_property\n", | |
" def fullname(self):\n", | |
" return \"xxx\"\n", | |
" \n", | |
"p = Person()\n", | |
"print p.fullname" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"stream": "stdout", | |
"text": [ | |
"myproperty.__init__ <function fullname at 0x10361fd70>\n", | |
"__get__ <__main__.Person object at 0x103621bd0> <class '__main__.Person'>\n", | |
"xxx\n" | |
] | |
} | |
], | |
"prompt_number": 38 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"Person.fullname" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"metadata": {}, | |
"output_type": "pyout", | |
"prompt_number": 39, | |
"text": [ | |
"<__main__.my_property at 0x103627d90>" | |
] | |
} | |
], | |
"prompt_number": 39 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"%%file fs.py\n", | |
"\"\"\"\n", | |
"Implement files and directories as Python objects.\n", | |
"\n", | |
"1. f.size - should give size of the file\n", | |
"2. f.name - should give the name\n", | |
"3. f.abspath - should give absolute path of the file\n", | |
"4. f.read() - should read all the contents of the file\n", | |
"5. f.parent - should give the parent directory\n", | |
"6. d['a.py'] - should give File object corresponding to a.py\n", | |
"7. len(d) - should tell how many files are there in that directory\n", | |
"\n", | |
"Hints: see os and os.path modules\n", | |
"\"\"\"\n", | |
"import os.path\n", | |
"\n", | |
"class File(object):\n", | |
" def __init__(self, path):\n", | |
" self.path = path\n", | |
" \n", | |
" @property\n", | |
" def size(self):\n", | |
" return os.stat(self.path).st_size\n", | |
"\n", | |
"class Directory(File):\n", | |
" pass\n", | |
"\n", | |
"if __name__ == \"__main__\":\n", | |
" f = File(\"/tmp/a.py\")\n", | |
" assert f.name == \"a.py\"\n", | |
" assert f.abspath == \"/tmp/a.py\" \n", | |
" assert isinstance(f.parent, Directory)\n", | |
" assert f.parent.path == '/tmp'\n", | |
" assert f.parent['a.py'].name == 'a.py'\n" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"stream": "stdout", | |
"text": [ | |
"Overwriting fs.py\n" | |
] | |
} | |
], | |
"prompt_number": 43 | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"## Context Managers" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"with open(\"numbers.txt\") as f:\n", | |
" print f.read()" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"stream": "stdout", | |
"text": [ | |
"1 one\n", | |
"2 two\n", | |
"3 three\n", | |
"4 four\n", | |
"5 five\n" | |
] | |
} | |
], | |
"prompt_number": 44 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"dir(f)" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"metadata": {}, | |
"output_type": "pyout", | |
"prompt_number": 45, | |
"text": [ | |
"['__class__',\n", | |
" '__delattr__',\n", | |
" '__doc__',\n", | |
" '__enter__',\n", | |
" '__exit__',\n", | |
" '__format__',\n", | |
" '__getattribute__',\n", | |
" '__hash__',\n", | |
" '__init__',\n", | |
" '__iter__',\n", | |
" '__new__',\n", | |
" '__reduce__',\n", | |
" '__reduce_ex__',\n", | |
" '__repr__',\n", | |
" '__setattr__',\n", | |
" '__sizeof__',\n", | |
" '__str__',\n", | |
" '__subclasshook__',\n", | |
" 'close',\n", | |
" 'closed',\n", | |
" 'encoding',\n", | |
" 'errors',\n", | |
" 'fileno',\n", | |
" 'flush',\n", | |
" 'isatty',\n", | |
" 'mode',\n", | |
" 'name',\n", | |
" 'newlines',\n", | |
" 'next',\n", | |
" 'read',\n", | |
" 'readinto',\n", | |
" 'readline',\n", | |
" 'readlines',\n", | |
" 'seek',\n", | |
" 'softspace',\n", | |
" 'tell',\n", | |
" 'truncate',\n", | |
" 'write',\n", | |
" 'writelines',\n", | |
" 'xreadlines']" | |
] | |
} | |
], | |
"prompt_number": 45 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"class DummyContext(object):\n", | |
" def __enter__(self):\n", | |
" print \"__enter__\"\n", | |
" return self\n", | |
" \n", | |
" def __exit__(self, type, exc, traceback):\n", | |
" print \"__exit__\", type, exc, traceback\n", | |
" return True\n", | |
" \n", | |
"with DummyContext() as d:\n", | |
" print d\n", | |
" raise Exception(\"foo\")" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"stream": "stdout", | |
"text": [ | |
"__enter__\n", | |
"<__main__.DummyContext object at 0x10362d450>\n", | |
"__exit__ <type 'exceptions.Exception'> foo <traceback object at 0x10362ad40>\n" | |
] | |
} | |
], | |
"prompt_number": 50 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"import os\n", | |
"class chdir(object):\n", | |
" def __init__(self, path):\n", | |
" self.path = path\n", | |
" self.old_path = None\n", | |
" \n", | |
" def __enter__(self):\n", | |
" self.old_path = os.getcwd()\n", | |
" os.chdir(self.path)\n", | |
" \n", | |
" def __exit__(self, type, exc, traceback):\n", | |
" os.chdir(self.old_path)\n", | |
"\n", | |
"print os.getcwd()\n", | |
"with chdir(\"/tmp\"):\n", | |
" print os.getcwd()\n", | |
" print os.listdir(os.getcwd())\n", | |
"print os.getcwd()" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"stream": "stdout", | |
"text": [ | |
"/Users/anand/Dropbox/Trainings/2013/advancedpython-dec-ga/notebook\n", | |
"/private/tmp\n", | |
"['.s.PGSQL.5432', 'a.pl', 'icssuis501', 'launch-89nLgT', 'launch-rAjNNy', 'launch-rEQZsu', 'launchd-137.64Yecb', 'mobilepartner.pid', 'UTPS_OnlineUpdate_Mutex.pid']\n", | |
"/Users/anand/Dropbox/Trainings/2013/advancedpython-dec-ga/notebook\n" | |
] | |
} | |
], | |
"prompt_number": 54 | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"**Problem** Implement a context manager `ignore_exception` that ignores all exceptions in that block.\n", | |
"\n", | |
" with ignore_exceptions():\n", | |
" open(\"no-such-file\").read()\n", | |
" print \"after with statement\"" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"**Class decorators**" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"def logit(obj):\n", | |
" print \"created\", obj.__name__\n", | |
" return obj\n", | |
"\n", | |
"@logit\n", | |
"class A(object):\n", | |
" pass\n", | |
"\n" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"stream": "stdout", | |
"text": [ | |
"created A\n" | |
] | |
} | |
], | |
"prompt_number": 55 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"A" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"metadata": {}, | |
"output_type": "pyout", | |
"prompt_number": 56, | |
"text": [ | |
"__main__.A" | |
] | |
} | |
], | |
"prompt_number": 56 | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"**Meta Classes**" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"print type(1)" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"stream": "stdout", | |
"text": [ | |
"<type 'int'>\n" | |
] | |
} | |
], | |
"prompt_number": 57 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"print type(int)" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"stream": "stdout", | |
"text": [ | |
"<type 'type'>\n" | |
] | |
} | |
], | |
"prompt_number": 58 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"print type(type)" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"stream": "stdout", | |
"text": [ | |
"<type 'type'>\n" | |
] | |
} | |
], | |
"prompt_number": 59 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"class A(object): pass\n", | |
"a = A()" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [], | |
"prompt_number": 60 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"type(a)" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"metadata": {}, | |
"output_type": "pyout", | |
"prompt_number": 61, | |
"text": [ | |
"__main__.A" | |
] | |
} | |
], | |
"prompt_number": 61 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"B = type(\"B\", (object,), {\"x\": 1})" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [], | |
"prompt_number": 62 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"B" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"metadata": {}, | |
"output_type": "pyout", | |
"prompt_number": 63, | |
"text": [ | |
"__main__.B" | |
] | |
} | |
], | |
"prompt_number": 63 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"B.x" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"metadata": {}, | |
"output_type": "pyout", | |
"prompt_number": 64, | |
"text": [ | |
"1" | |
] | |
} | |
], | |
"prompt_number": 64 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"B.__name__" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"metadata": {}, | |
"output_type": "pyout", | |
"prompt_number": 65, | |
"text": [ | |
"'B'" | |
] | |
} | |
], | |
"prompt_number": 65 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"class type2(type):\n", | |
" def __init__(self, name, bases, attrs):\n", | |
" type.__init__(self, name, bases, attrs)\n", | |
" print name, bases, attrs\n", | |
" \n", | |
"B2 = type2(\"B2\", (object,), {\"x\": 1})" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"stream": "stdout", | |
"text": [ | |
"B2 (<type 'object'>,) {'x': 1}\n" | |
] | |
} | |
], | |
"prompt_number": 66 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"B2" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"metadata": {}, | |
"output_type": "pyout", | |
"prompt_number": 67, | |
"text": [ | |
"__main__.B2" | |
] | |
} | |
], | |
"prompt_number": 67 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"type(B2)" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"metadata": {}, | |
"output_type": "pyout", | |
"prompt_number": 68, | |
"text": [ | |
"__main__.type2" | |
] | |
} | |
], | |
"prompt_number": 68 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"class C2(B2):\n", | |
" pass" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"stream": "stdout", | |
"text": [ | |
"C2 (<class '__main__.B2'>,) {'__module__': '__main__'}\n" | |
] | |
} | |
], | |
"prompt_number": 69 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"class B3(object):\n", | |
" __metaclass__ = type2" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"stream": "stdout", | |
"text": [ | |
"B3 (<type 'object'>,) {'__module__': '__main__', '__metaclass__': <class '__main__.type2'>}\n" | |
] | |
} | |
], | |
"prompt_number": 70 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"type(B3)" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"metadata": {}, | |
"output_type": "pyout", | |
"prompt_number": 71, | |
"text": [ | |
"__main__.type2" | |
] | |
} | |
], | |
"prompt_number": 71 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"class C3(B3): pass" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"stream": "stdout", | |
"text": [ | |
"C3 (<class '__main__.B3'>,) {'__module__': '__main__'}\n" | |
] | |
} | |
], | |
"prompt_number": 72 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"class LoggingMeta(type):\n", | |
" def __init__(self, name, bases, attrs):\n", | |
" type.__init__(self, name, bases, attrs)\n", | |
" print \"creating class\", name" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [], | |
"prompt_number": 73 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"class A(object):\n", | |
" __metaclass__ = LoggingMeta\n", | |
" " | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"stream": "stdout", | |
"text": [ | |
"creating class A\n" | |
] | |
} | |
], | |
"prompt_number": 74 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"class B(A): pass" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"stream": "stdout", | |
"text": [ | |
"creating class B\n" | |
] | |
} | |
], | |
"prompt_number": 75 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"%%file urls2.py\n", | |
"\n", | |
"urls = []\n", | |
"\n", | |
"class metapage(type):\n", | |
" def __init__(self, name, bases, attrs):\n", | |
" type.__init__(self, name, bases, attrs)\n", | |
" path = attrs.get(\"path\", \"/\" + name)\n", | |
" urls.append((path, self))\n", | |
" \n", | |
"class page(object):\n", | |
" __metaclass__ = metapage\n", | |
" \n", | |
"# get rid of page class from urls\n", | |
"urls = []\n", | |
" \n", | |
"class hello(page):\n", | |
" def GET(self):\n", | |
" return \"hello world!\"\n", | |
" \n", | |
"class bye(page):\n", | |
" path = \"/goodbye\"\n", | |
" def GET(self):\n", | |
" return \"good bye!\"\n", | |
" \n", | |
"print urls" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"stream": "stdout", | |
"text": [ | |
"Overwriting urls2.py\n" | |
] | |
} | |
], | |
"prompt_number": 83 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"!python urls2.py" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"stream": "stdout", | |
"text": [ | |
"[('/hello', <class '__main__.hello'>), ('/goodbye', <class '__main__.bye'>)]\r\n" | |
] | |
} | |
], | |
"prompt_number": 84 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [] | |
} | |
], | |
"metadata": {} | |
} | |
] | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment