Commit cbef1e07 authored by christian.foerster's avatar christian.foerster

update

parent 0040f636
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Python Tutorial Part 2 - Advanced Topics\n",
"\n",
"## Object Oriented Programming (OOP)\n",
"\n",
"OOP is a programming paradigm based on the concept of \"objects\", which can contain data, in the form of attributes and code, in the form of methods.\n",
"It's a different way of you thinking about your model/problem. Instead of thinking of a problem as a sequence of commands that need to be executed (procedural, **linear**), you identify single processes/actors and define their attributes and functionalities, so that they can interact with other actors (**nonlinear**).\n",
"\n",
"**Example Problem:\n",
"Create a simple Notepad**\n",
"\n",
"You'll want to be able to add and delete notes. And for each note you want to be able to add, delete and mark (as done) entries. The Notepad should also have a memory of which Note is selected."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Procedural**\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"notes = {}\n",
"selectedNote = None\n",
"\n",
"def addNote(notes, noteName):\n",
" global selectedNote\n",
" selectedNote = noteName\n",
" notes[noteName]={}\n",
" return notes\n",
"\n",
"def deleteNote(notes,noteName):\n",
" global selectedNote\n",
" selectedNote = None\n",
" del notes[noteName]\n",
" return notes\n",
"\n",
"def _noteNameCheck(noteName):\n",
" global selectedNote\n",
" if noteName is None and selectedNote is None:\n",
" raise ValueError(\"Please provide a noteName.\")\n",
" elif noteName is None:\n",
" noteName = selectedNote\n",
" return noteName\n",
"\n",
"def addEntry(notes, entry, noteName = None):\n",
" noteName = _noteNameCheck(noteName)\n",
" notes[noteName][entry]=\"unmarked\"\n",
" return notes\n",
"\n",
"def deleteEntry(notes, entry, noteName = None):\n",
" noteName = _noteNameCheck(noteName)\n",
" del notes[noteName][entry]\n",
" return notes\n",
"\n",
"def markEntry(notes, entry, noteName = None):\n",
" noteName = _noteNameCheck(noteName)\n",
" notes[noteName][entry]=\"marked\"\n",
" return notes\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"{'ShoppingList': {'coffee': 'unmarked',\n",
" 'milk': 'unmarked',\n",
" 'bread': 'unmarked',\n",
" 'chocolate': 'marked'}}"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"addNote(notes, \"ShoppingList\")\n",
"addEntry(notes,\"coffee\")\n",
"addEntry(notes,\"milk\")\n",
"addEntry(notes,\"bread\")\n",
"addEntry(notes,\"chocolate\")\n",
"markEntry(notes,\"chocolate\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**OOP**"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"class Notepad():\n",
" def __init__(self):\n",
" self.notes = {}\n",
" self.selectedNote=None\n",
" return\n",
" \n",
" def _noteNameCheck(self,noteName):\n",
" if noteName is None and self.selectedNote is None:\n",
" raise ValueError(\"Please provide a noteName.\")\n",
" elif noteName is None:\n",
" noteName = self.selectedNote\n",
" return noteName\n",
" \n",
" def addNote(self, noteName):\n",
" self.selectedNote=noteName\n",
" self.notes[noteName] = {}\n",
" return self.notes\n",
" \n",
" def deleteNote(self, noteName=None):\n",
" noteName = self._noteNameCheck(noteName)\n",
" del self.notes[noteName]\n",
" self.selectedNote = None \n",
" return self.notes\n",
" \n",
" def addEntry(self, entry, noteName=None):\n",
" noteName = self._noteNameCheck(noteName)\n",
" self.notes[noteName][entry]=\"unmarked\"\n",
" return self.notes\n",
" \n",
" def deleteEntry(self, entry, noteName=None):\n",
" noteName = self._noteNameCheck(noteName)\n",
" del self.notes[noteName][entry]\n",
" return self.notes\n",
" \n",
" def markEntry(self, entry, noteName=None):\n",
" noteName = self._noteNameCheck(noteName)\n",
" self.notes[noteName][entry]=\"marked\"\n",
" return self.notes"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"{'Shopping': {'coffee': 'unmarked',\n",
" 'milk': 'unmarked',\n",
" 'break': 'unmarked',\n",
" 'chocolate': 'marked'}}"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"NotepadInstance = Notepad()\n",
"NotepadInstance.addNote(\"Shopping\")\n",
"NotepadInstance.addEntry(\"coffee\")\n",
"NotepadInstance.addEntry(\"milk\")\n",
"NotepadInstance.addEntry(\"break\")\n",
"NotepadInstance.addEntry(\"chocolate\")\n",
"NotepadInstance.markEntry(\"chocolate\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"So for simple programs, there is basically not difference between these programming styles. But as soon as it gets more complicated OOP shines, because different parts of the program can be seperated more clearly. Image you want to design a plottling library...\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 4 Pillars of OOP\n",
"- Inheritance (a way to reuse your code)\n",
"- Abstraction (showing only essential features hiding details)\n",
"- Encapsulation (bind data variables and functions together in a class)\n",
"- Polymorphism (create functions with same name and different arguments, redefine functions)\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [],
"source": [
"# Parent class\n",
"class Dog:\n",
" # Class attribute\n",
" species = 'mammal'\n",
"\n",
" # Initializer / Instance attributes\n",
" def __init__(self, name, age):\n",
" self.name = name\n",
" self.age = age\n",
"\n",
" # instance method\n",
" def description(self):\n",
" return \"{} is {} years old\".format(self.name, self.age)\n",
"\n",
" # instance method\n",
" def speak(self, sound):\n",
" return \"{} says {}\".format(self.name, sound)\n",
"\n",
" \n",
"# Child class (inherits from Dog() class)\n",
"class RussellTerrier(Dog):\n",
" def run(self, speed):\n",
" return \"{} runs {}\".format(self.name, speed)\n",
"\n",
"\n",
"# Child class (inherits from Dog() class)\n",
"class Bulldog(Dog):\n",
" def run(self, speed):\n",
" return \"{} runs {}\".format(self.name, speed)"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Jim is 12 years old\n",
"Jim runs slowly\n",
"True\n",
"True\n",
"False\n",
"False\n"
]
}
],
"source": [
"# Child classes inherit attributes and\n",
"# behaviors from the parent class\n",
"jim = Bulldog(\"Jim\", 12)\n",
"print(jim.description())\n",
"\n",
"# Child classes have specific attributes\n",
"# and behaviors as well\n",
"print(jim.run(\"slowly\"))\n",
"\n",
"# Is jim an instance of Dog()?\n",
"print(isinstance(jim, Dog))\n",
"\n",
"# Is julie an instance of Dog()?\n",
"julie = Dog(\"Julie\", 100)\n",
"print(isinstance(julie, Dog))\n",
"\n",
"# Is johnny walker an instance of Bulldog()\n",
"johnnywalker = RussellTerrier(\"Johnny Walker\", 4)\n",
"print(isinstance(johnnywalker, Bulldog))\n",
"\n",
"# Is julie and instance of jim?\n",
"print(isinstance(julie, RussellTerrier))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Useful Example**"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[2019-06-28 16:07:59 - OneOfMany] - Instance initiated with...\n",
" Arguments: ('Here', 'are', 'some', 'arguments', '.')\n",
" Kwarguments: {'ThisIsADictArgument': 'check me out'}\n",
"[2019-06-28 16:07:59 - VarMemory] - Checking if logfile exists.\n",
"[2019-06-28 16:07:59 - VarMemory] - Writing logfile.\n",
"[2019-06-28 16:07:59 - VarMemory] - Tracker logged ac:33\n",
"[2019-06-28 16:07:59 - VarMemory] - Writing logfile.\n",
"[2019-06-28 16:07:59 - VarMemory] - Tracker logged {'abc': [3, 4, 5], 'bcd': 44}\n"
]
}
],
"source": [
"import sys, time, json, os\n",
"\n",
"class VerboseHandler:\n",
" verboseFile = None\n",
" verbosePrint = True\n",
" \n",
" def __verbose(self,*args, **kwargs):\n",
" niceFormatString = \"[{} - {}]\".format(time.strftime(\"%Y-%m-%d %X\"),self.__class__.__name__ )\n",
" \n",
" # taking care of indentation\n",
" length = len(niceFormatString)+3\n",
" args_updated = [a.replace(\"\\n\",\"\\n\"+\" \"*length) for a in args]\n",
" \n",
" print(niceFormatString, end=\" - \")\n",
" print(*args_updated, **kwargs)\n",
" \n",
" def verbose(self, *args, **kwargs):\n",
" \"\"\"\n",
" this method has the same arguments as print()\n",
" \"\"\"\n",
" if self.verbosePrint:\n",
" self.__verbose(*args, **kwargs)\n",
"\n",
" if self.verboseFile is not None:\n",
"\n",
" original_stdout = sys.stdout\n",
"\n",
" with open(verboseFile, \"a+\") as stream:\n",
" sys.stdout = stream\n",
" self.__verbose(*args, **kwargs)\n",
" \n",
" sys.stdout = original_stdout\n",
" \n",
" return\n",
" \n",
"\n",
"class VarMemory(VerboseHandler):\n",
" logfile = \"variable.txt\"\n",
" \n",
" def __init__(self):\n",
" self.__vardict = {}\n",
" if self.__file_exists():\n",
" self.__read_dict()\n",
" return\n",
"\n",
" def __file_exists(self):\n",
" self.verbose(\"Checking if logfile exists.\")\n",
" return os.path.exists(self.logfile)\n",
"\n",
" def __write_dict(self):\n",
" self.verbose(\"Writing logfile.\")\n",
" with open(self.logfile, \"w\") as lfile:\n",
" json.dump(self.__vardict, lfile, indent=4)\n",
" return\n",
" \n",
" def __read_dict(self):\n",
" self.verbose(\"Reading logfile.\")\n",
" with open(self.logfile, \"r\") as lfile:\n",
" self.__vardict = json.load(lfile)\n",
" return\n",
"\n",
" def log(self, key, value):\n",
" self.__vardict[key] = value\n",
" self.__write_dict()\n",
" self.verbose(\"Tracker logged {}:{}\".format(str(key),str(value)))\n",
" return\n",
"\n",
" def log_from_dict(self, dictionary):\n",
" self.__vardict.update(dictionary)\n",
" self.__write_dict()\n",
" self.verbose(\"Tracker logged {}\".format(str(dictionary)))\n",
" return\n",
" \n",
" # magic method to enable indexing of instance\n",
" def __getitem__(self, key):\n",
" return self.__vardict[key]\n",
" \n",
" # magic method to enable deleting via indexing the instance\n",
" def __delitem__(self, key):\n",
" self.verbose(\"Deleting log varibles - {}:{}\".format(key,self.__vardict[key]))\n",
" del self.__vardict[key]\n",
" self.__write_dict()\n",
" return\n",
" \n",
" # magic method to enable iteration via the instance\n",
" def __iter__(self):\n",
" return iter(self.__vardict)\n",
"\n",
" \n",
"class OneOfMany(VerboseHandler):\n",
" def __init__(self,*args,**kwargs):\n",
" self.verbose(\"Instance initiated with...\\nArguments: {}\\nKwarguments: {}\".format(str(args),str(kwargs)))\n",
" \n",
" \n",
"oom=OneOfMany(\"Here\",\"are\",\"some\",\"arguments\",\".\",ThisIsADictArgument=\"check me out\")\n",
"\n",
"vr = VarMemory()\n",
"vr.log(\"ac\",33)\n",
"vr.log_from_dict({\"abc\":[3,4,5],\"bcd\":44})"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"33\n",
"[3, 4, 5]\n",
"44\n"
]
}
],
"source": [
"for entry in vr:\n",
" print(vr[entry])"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Structuring your code"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Performance\n",
"\n",
"- Numpy is fast! Why?\n",
" - try to stick with one variable type. Don't use lists and arrays and mix it all up\n",
"- what needs to be in a loop what not. \n",
"- trade off memory, performance"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Large Projects\n",
"Pycharm, Git, Debugging, Naming conventions, goot practice"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [],
"source": [
"class Tank:\n",
" def __init__(self, tank_id, level, rate, upstream_tanks=None):\n",
" self.tank_id = tank_id\n",
" self.level = level\n",
" self.rate = rate\n",
" self.upstream_tanks = upstream_tanks\n",
" \n",
" @property # allows use of the method without brackets \n",
" def Q(self):\n",
" return self.level * self.rate\n",
" \n",
" def fill_tank(self):\n",
" if self.upstream_tanks is not None:\n",
" for uptank in self.upstream_tanks:\n",
" # recursion (sort of)\n",
" uptank.fill_tank() \n",
" \n",
" uptank.level -= uptank.Q\n",
" self.level += uptank.Q\n",
" \n",
" def __repr__(self):\n",
" return \"tank_id: {}\\nlevel: {}\\nrate: {}\".format(self.tank_id,self.level,self.rate)\n",
" \n",
"def initiate_tanks(network_structure, attributes):\n",
" # init all tanks without upstream tanks\n",
" tanks = {}\n",
" for tank_id in attributes:\n",
" level = attributes[tank_id][0]\n",
" rate = attributes[tank_id][1]\n",
" tanks[tank_id] = Tank(tank_id, level, rate, upstream_tanks=None)\n",
" # add upstream tanks\n",
" for tank_id in network_structure:\n",
" tanks[tank_id].upstream_tanks = [tanks[tank_id_up] for tank_id_up in network_structure[tank_id]]\n",
" return tanks\n",
"\n",
"def get_levels_upstream(fill_dict,tank):\n",
" fill_dict[tank.tank_id].append(tank.level)\n",
" if tank.upstream_tanks is not None:\n",
" for uptank in tank.upstream_tanks:\n",
" get_levels_upstream(fill_dict, uptank)\n"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [],
"source": [
"network_structure = {6:[4,5],4:[1,2],5:[3]}\n",
"attributes = {1:(10, 0.0),\n",
" 2:(20, 0.06),\n",
" 3:(15, 0.9),\n",
" 4:(8, 0.3),\n",
" 5:(44, 0.5),\n",
" 6:(2.5, 0)}"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [],
"source": [
"final_tank = initiate_tanks(network_structure,attributes)[6]\n",
"levels = {k:[] for k in range(7)[1:]}\n",
"for dt in range(100):\n",
" get_levels_upstream(levels,final_tank)\n",
" final_tank.fill_tank()\n",
" "
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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\n",
"text/plain": [
"<Figure size 864x576 with 6 Axes>"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"# plotting simulation\n",
"import matplotlib.pyplot as plt\n",
"fig, axis = plt.subplots(6,1,figsize = (12,8))\n",
"for idx, ax in enumerate(axis):\n",
" ax.plot(levels[idx+1])\n",
" ax.set_title(idx+1)\n",
"plt.tight_layout()\n",
"plt.show()"
]
},
{
"cell_type": "code",
"execution_count": 45,
"metadata": {},
"outputs": [],
"source": [
"\"\"\"Version 1\"\"\"\n",
"# simulate 2 tanks -> one filling the other! tank_area=1!\n",
"\n",
"level_1 = 50\n",
"rate_1 = 0.21\n",
"level_2 = 0\n",
"for t in range(100):\n",
" level_2 += level_1*rate_1\n",
" level_1 -= level_1*rate_1\n",
" \n",
"# code quick and dirty!! "
]
},