{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "[Home](Home.ipynb)\n", "\n", "# Bridge to OOP\n", "\n", "The named tuple, in the collections module, lets us reach into a sequence both by numeric index, as usual with tuples, and by attribute, meaning each tuple made with a template will have the same fixed attribute names.\n", "\n", "For example:" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "from collections import namedtuple" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "Shape = namedtuple(\"Poly\", \"Faces Vertexes Edges\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The name ```Shape``` now points to an object in memory that serves as a callable, a kind of factory, for making any number of Shape things (a subclass of tuple, one may think of it). " ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Poly(Faces=4, Vertexes=4, Edges=6)" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "tetra = Shape(4, 4, 6)\n", "tetra" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Poly(Faces=6, Vertexes=8, Edges=12)" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "cube = Shape(Vertexes=8, Edges=12, Faces=6) # named args\n", "cube" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\"Shape things\" represent themselves with whatever string is provided, as the leftmost argument." ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "octa = Shape(Faces=8, Vertexes=6, Edges=12)\n", "icosa = Shape(Faces=20, Vertexes=12, Edges=30)" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "dodeca = Shape(12, 12, 24)" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Poly(Faces=20, Vertexes=12, Edges=30)" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "icosa" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If you're following the action, you'll see we have created a few Shape type namedtuples. Now we can get the data in namedtuple s by saying ```s.Edges``` instead of ```s[2]```." ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Tsk Tsk, you broke Euler's rule\n" ] } ], "source": [ "all_shapes = icosa, cube, tetra, octa, dodeca\n", "\n", "for s in all_shapes:\n", " # V + F == E + 2 (Euler's Law for Polyhedra with No Holes)\n", " try:\n", " assert s.Edges + 2 == (s.Vertexes + s.Faces)\n", " except AssertionError:\n", " print(\"Tsk Tsk, you broke Euler's rule\")" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "4" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "getattr(tetra, 'Faces')" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "hasattr(icosa, 'Edges')" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(4, 4, 6)" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "tetra[0], tetra[1], tetra[2]" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(20, 12, 30, 4, 4, 6)" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "*icosa, *tetra" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(Poly(Faces=20, Vertexes=12, Edges=30), Poly(Faces=4, Vertexes=4, Edges=6))" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "icosa, tetra" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Exercise\n", "\n", "You realize future designs to add a database on the back end necessitate each Shape having an additional attribute, namely a Name. The Name would be the exact type of Polyhedron being defined, such as \"Octahedron\" or \"Tetrahedron\".\n", "\n", "Make a new Shape below, that has this additional attribute and make it do tricks." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Python's Object Model\n", "\n", "Note on style: blank lines cost only a single byte apiece, yet add a lot to readability. Separate methods with a space." ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [], "source": [ "class Dog:\n", " \n", " def __init__(me, name):\n", " me.name = name # use of 'me' versus 'self' nonstandard!\n", " \n", " def bark(me, n=1):\n", " \"bark n times\"\n", " print(me.name, \"says\", \"Bark! \" * n)" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Rover says Bark! Bark! Bark! Bark! Bark! \n" ] } ], "source": [ "the_dog = Dog(\"Rover\")\n", "the_dog.bark(5)" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Rover says Bark! Bark! Bark! Bark! Bark! \n" ] } ], "source": [ "Dog.bark(the_dog, 5)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Inheritance\n", "\n", "Inheritance is a standard part of the Object Model, in any object oriented language. An Animal class, more general than its more specialized child classes, such as Dog and Cat, provides a common core or ancestor.\n", "\n", "The builtin super() figures out who the ancestor will be, according to a kind of search algorithm which traces a \"method resolution order\" (path through ancestor classes). \n", "\n", "When initializing a new Dog, invoke the ancestral constructor as well, as that's where an empty stomach gets added, for use with an eat() method." ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [], "source": [ "class Animal:\n", " \n", " def __init__(self):\n", " self.stomach = [ ] # self is standard\n", " \n", " def eat(self, food):\n", " self.stomach.append(food)\n", " \n", "class Dog(Animal): # does everything an Animal might do, and more\n", " \n", " def __init__(me, name):\n", " me.name = name # use of 'me' versus 'self' nonstandard!\n", " super().__init__() # lets get us a stomach\n", " \n", " def bark(me, n=1):\n", " \"bark n times\"\n", " print(me.name, \"says\", \"Bark! \" * n)" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['marshmellow']" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "der_dog = Dog(\"Rover\")\n", "der_dog.eat(\"marshmellow\")\n", "der_dog.stomach" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(__main__.Dog, __main__.Animal, object)" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Dog.__mro__ # the order in which to search for a method name" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[Object Oriented Programming (OOP)](ObjectOrientedProgramming.ipynb)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Bookmarking Hyperlinks\n", "\n", "Here's another example of named tuples in action." ] }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Bookmark(place='Anaconda.org', url='http://anaconda.org', tags='tool')\n", "-\n", "Bookmark(place='Python.org', url='http://python.org', tags='source')\n", "-\n", "Bookmark(place='Python Docs', url='https://docs.python.org/3/', tags='docs')\n", "-\n", "Bookmark(place=\"''New Math'' by Tom Lehrer (animated)\", url='https://youtu.be/UIKGV2cTgqA', tags='comedy')\n", "-\n", "Bookmark(place='Spaghetti Code', url='http://c2.com/cgi/wiki?SpaghettiCode', tags='glossary')\n", "-\n", "Bookmark(place='Structured Programming', url='http://c2.com/cgi/wiki?StructuredProgramming', tags='glossary, history')\n", "-\n", "Bookmark(place='Map of Languages', url='http://archive.oreilly.com/pub/a/oreilly//news/languageposter_0504.html', tags='docs')\n", "-\n", "Bookmark(place='XKCD', url='http://xkcd.com', tags='comedy')\n", "-\n", "Bookmark(place='Will Geeks Rule? CBS News (world domination meme)', url='http://www.cbsnews.com/news/will-geeks-rule-the-world/', tags='glossary, comedy')\n", "-\n", "Bookmark(place='Django', url='https://docs.djangoproject.com/', tags='source')\n", "-\n", "Bookmark(place='PythonAnywhere', url='https://www.pythonanywhere.com/', tags='tool')\n", "-\n", "Bookmark(place='CodeAcademy: Python', url='https://www.codecademy.com/learn/python', tags='docs')\n", "-\n", "Bookmark(place='Unicode on Youtube', url='https://www.youtube.com/watch?v=Z_sl99D2a18', tags='docs, glossary')\n", "-\n", "Bookmark(place='In Defense of Ada', url='http://www.grunch.net/synergetics/adaessay.html', tags='comedy, history')\n", "-\n", "Bookmark(place='Grace Hopper on Letterman', url='https://www.youtube.com/watch?v=1-vcErOPofQ', tags='source')\n", "-\n", "Bookmark(place='The Mind of a Genius: John von Neumann', url='https://www.youtube.com/watch?v=XZ9tt72feL8', tags='docs')\n", "-\n", "Bookmark(place='World Domination meme', url='https://www.google.com/search?q=linux+world+domination&safe=off&source=lnms&tbm=isch', tags='glossary, comedy, culture')\n", "-\n", "Bookmark(place='Warriors of the Net', url='https://www.youtube.com/watch?v=PBWhzz_Gn10', tags='docs, glossary, comedy')\n", "-\n", "Bookmark(place='LAMP stack', url='https://www.google.com/search?q=lamp+stack&safe=off&biw=787&bih=535&source=lnms&tbm=isch', tags='glossary')\n", "-\n", "Bookmark(place='LAMP stack (Wikipedia)', url='https://en.wikipedia.org/wiki/LAMP_(software_bundle)', tags='glossary')\n", "-\n", "Bookmark(place='Find string in string in SQLite', url='https://stackoverflow.com/questions/3498844/sqlite-string-contains-other-string-query', tags='docs')\n", "-\n", "Bookmark(place='What Python IDE is best?', url='https://www.quora.com/What-is-your-favorite-IDE-for-Python-programming-and-why', tags='tool')\n", "-\n", "Bookmark(place='More Help with Python', url='https://medium.com/@kirbyurner/more-help-with-python-9afe2d0affe8', tags='docs')\n", "-\n", "Bookmark(place='Microsoft Azure', url='https://azure.microsoft.com/en-us/', tags='cloud')\n", "-\n", "Bookmark(place='AWS', url='https://aws.amazon.com/', tags='cloud')\n", "-\n" ] } ], "source": [ "# %%writefile make_links_v4.py\n", "\"\"\"\n", "Created on Thu Jan 28 21:27:07 2016\n", "\n", "@author: kurner\n", "\n", "A namedtuple is a subclass of tuple allowing for named\n", "columns and therefore dot notation access, treating \n", "elements as named attributes.\n", "\n", "Bookmark(place='Anaconda.org', url='http://anaconda.org', tags='tool')\n", "\"\"\"\n", "\n", "from collections import namedtuple\n", "from context1 import DB\n", "\n", "PRINT = True # make true if you wish screen noise (echo of bookmarks)\n", "\n", "Bmk = namedtuple('Bookmark', 'place url tags')\n", "\n", "# tuple of tuples\n", "tuples = (\n", " (\"Anaconda.org\", \n", " \"http://anaconda.org\", \n", " \"tool\"),\n", " (\"Python.org\", \n", " \"http://python.org\", \n", " \"source\"),\n", " (\"Python Docs\", \n", " \"https://docs.python.org/3/\", \n", " \"docs\"),\n", " (\"''New Math'' by Tom Lehrer (animated)\",\n", " \"https://youtu.be/UIKGV2cTgqA\", \n", " \"comedy\"),\n", " (\"Spaghetti Code\", \n", " \"http://c2.com/cgi/wiki?SpaghettiCode\", \n", " \"glossary\"),\n", " (\"Structured Programming\", \n", " \"http://c2.com/cgi/wiki?StructuredProgramming\", \n", " \"glossary, history\"),\n", " (\"Map of Languages\", \n", " \"http://archive.oreilly.com/pub/a/oreilly//news/languageposter_0504.html\", \n", " \"docs\"),\n", " (\"XKCD\", \"http://xkcd.com\", \"comedy\"),\n", " (\"Will Geeks Rule? CBS News (world domination meme)\",\n", " \"http://www.cbsnews.com/news/will-geeks-rule-the-world/\", \n", " \"glossary, comedy\"),\n", " (\"Django\",\"https://docs.djangoproject.com/\", \"source\"),\n", " (\"PythonAnywhere\",\"https://www.pythonanywhere.com/\", \"tool\"),\n", " (\"CodeAcademy: Python\",\n", " \"https://www.codecademy.com/learn/python\", \n", " \"docs\"),\n", " (\"Unicode on Youtube\", \n", " \"https://www.youtube.com/watch?v=Z_sl99D2a18\", \n", " \"docs, glossary\"),\n", " (\"In Defense of Ada\", \n", " \"http://www.grunch.net/synergetics/adaessay.html\", \"comedy, history\"),\n", " (\"Grace Hopper on Letterman\", \n", " \"https://www.youtube.com/watch?v=1-vcErOPofQ\", \"source\"),\n", " (\"The Mind of a Genius: John von Neumann\", \n", " \"https://www.youtube.com/watch?v=XZ9tt72feL8\", \"docs\"),\n", " (\"World Domination meme\", \n", " \"https://www.google.com/search?q=linux+world+domination&safe=off&source=lnms&tbm=isch\", \n", " \"glossary, comedy, culture\"),\n", " (\"Warriors of the Net\", \n", " \"https://www.youtube.com/watch?v=PBWhzz_Gn10\", \n", " \"docs, glossary, comedy\"),\n", " (\"LAMP stack\", \n", " \"https://www.google.com/search?q=lamp+stack&safe=off&biw=787&bih=535&source=lnms&tbm=isch\", \n", " \"glossary\"),\n", " (\"LAMP stack (Wikipedia)\",\n", " \"https://en.wikipedia.org/wiki/LAMP_(software_bundle)\", \n", " \"glossary\"),\n", " (\"Find string in string in SQLite\", \n", " \"https://stackoverflow.com/questions/3498844/sqlite-string-contains-other-string-query\", \n", " \"docs\"),\n", " (\"What Python IDE is best?\", \"https://www.quora.com/What-is-your-favorite-IDE-for-Python-programming-and-why\",\n", " \"tool\"),\n", " (\"More Help with Python\", \"https://medium.com/@kirbyurner/more-help-with-python-9afe2d0affe8\",\n", " \"docs\"),\n", " (\"Microsoft Azure\", \"https://azure.microsoft.com/en-us/\", \"cloud\"),\n", " (\"AWS\", \"https://aws.amazon.com/\", \"cloud\")\n", ")\n", "\n", "# lets make these namedtuples instead OK?\n", "# *tup explodes each tuple into two positionals, what Bmk expects\n", "\n", "def bumpy():\n", " \"\"\"\n", " if you expect problems in the input\n", " \"\"\"\n", " the_list = []\n", " for tup in tuples:\n", " try:\n", " the_list.append(Bmk(*tup))\n", " except TypeError:\n", " print(\"Ill-formed tuple:\", tup)\n", " return the_list\n", "\n", "def smooth():\n", " \"\"\"\n", " if you expect smooth sailing i.e. no problems with tuples\n", " \"\"\"\n", " the_list = [Bmk(*tup) for tup in tuples] # list comprehension! \n", " return the_list\n", " \n", "def printall(): \n", " for bmk in bookmarks:\n", " # Bookmark(place='Anaconda.org', url='http://anaconda.org')\n", " print(bmk) # notice format of output: __repr__\n", " print(\"-\")\n", "\n", "if __name__ == \"__main__\":\n", "\n", " bookmarks = bumpy()\n", " # bookmarks = smooth()\n", "\n", " if PRINT:\n", " printall()\n", " \n", " # login\n", " with DB(\"bookmarks.db\") as db:\n", "\n", " # https://www.sqlite.org/lang_droptable.html\n", " # DB API ???\n", " db.curs.execute(\"\"\"DROP TABLE IF EXISTS Bookmarks\"\"\")\n", " db.curs.execute(\"\"\"CREATE TABLE Bookmarks\n", " (bk_place text PRIMARY KEY,\n", " bk_url text,\n", " bk_tags text)\"\"\")\n", " \n", " for bmk in sorted(bookmarks):\n", " query = (\"INSERT INTO Bookmarks \" \n", " \"(bk_place, bk_url, bk_tags) \"\n", " \"VALUES ('{}', '{}', '{}')\".format(bmk.place, bmk.url, bmk.tags))\n", " # print(query)\n", " db.curs.execute(query)\n", " db.conn.commit()" ] }, { "cell_type": "code", "execution_count": 35, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "('AWS', 'https://aws.amazon.com/', 'cloud')\n", "('Microsoft Azure', 'https://azure.microsoft.com/en-us/', 'cloud')\n" ] } ], "source": [ "# %load bookmarks.py\n", "#!/usr/bin/env python3\n", "\"\"\"\n", "Created on Thu Oct 11 11:38:26 2018\n", "\n", "@author: Kirby Urner\n", "\n", "How to use LIKE keyword in SQLite:\n", "https://stackoverflow.com/questions/3498844/sqlite-string-contains-other-string-query\n", "\n", "\"\"\"\n", "\n", "import sqlite3 as sql\n", "\n", "class DB:\n", " \"\"\"\n", " I connect you to a database, use me as a \n", " context manager\n", " \"\"\"\n", " \n", " def __init__(self, target):\n", " # target to dial\n", " self.source = target\n", " \n", " def connect(self):\n", " \"\"\"\n", " dial the target and connect\n", " \"\"\"\n", " # we'll be needing these\n", " self.conn = sql.connect(self.source)\n", " self.curs = self.conn.cursor()\n", " \n", " def __enter__(self):\n", " \"\"\"\n", " upon entering the context, I do my job \n", " \"\"\"\n", " self.connect() # delegating...\n", " return self # I am valuable\n", " \n", " def __exit__(self, *oops):\n", " if oops:\n", " return False\n", " return True\n", " \n", "def tag_filter(the_tag):\n", " \n", " with DB(\"bookmarks.db\") as db:\n", " # see Stackoverflow link in module's __doc__\n", " db.curs.execute(\"SELECT * FROM \"\n", " \"Bookmarks WHERE \" # whoah, this OK?\n", " \"bk_tags LIKE ? \", (the_tag,))\n", " results = list(db.curs.fetchall())\n", " # database closes through __exit__, yahoo! \n", " return results\n", "\n", "if __name__ == \"__main__\":\n", " # try %comedy% %docs% %tool% and %glossary% too\n", " for record in tag_filter(\"%cloud%\"):\n", " print( record )" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.9" } }, "nbformat": 4, "nbformat_minor": 4 }