Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
136 changes: 58 additions & 78 deletions tutorials/OOB_EC/OOP_1.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"metadata": {},
"source": [
"## Introduction to OOP in Python, Part 1\n",
"An Object is a type of data structure that contains both attributes (or properties) and methods (essencially functions that act upon the object's attributes). Attributes themselves can be other objects of the same or different class. A class definition is basically the template for object's attributes and methods. A specific object is said to be an instance of its class."
"An Object is a type of data structure that contains both attributes (or properties) and methods - essentially functions that act upon the object's attributes. Attributes themselves can be other objects of the same or different class. A class definition is basically the template for object's attributes and methods. A specific object is said to be an instance of its class."
]
},
{
Expand All @@ -17,13 +17,13 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"The task we will set ouselves is to build Python classes that enable us to represent algebraic expression trees, for example, $ ((5 + z) / -8) * (4 ^ 2) $ is represented as: \n",
"The task we will set ourselves is to build Python classes that enable us to represent algebraic expression trees, for example, $ ((5 + z) / -8) * (4 ^ 2) $ is represented as: \n",
"\n",
"![image.png](attachment:120c4f94-e050-4313-88d8-50cccea884a7.png)\n",
"\n",
"From wikipedia : https://en.wikipedia.org/wiki/Binary_expression_tree\n",
"From Wikipedia : https://en.wikipedia.org/wiki/Binary_expression_tree\n",
"\n",
"We may go on to see how we can use such trees for *Evolutionary Computing* in later tutorials."
"We may go on to see how we can use such trees for *Evolutionary Computing* in later tutorial set."
]
},
{
Expand Down Expand Up @@ -52,21 +52,25 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"Function names that begin and end with double underscore are used by Python to define a <i>protocol</i><sup>1</sup>;\n",
"in this case \\_\\_init\\_\\_ is part of the class protocol and defines how a specific instance of the new\n",
"Function names that begin and end with double underscore are used by Python to define a *protocol*<sup>1</sup>;\n",
"in this case `__init__` is part of the class protocol and defines how a specific instance of the new\n",
"class will be initialized, and is called automatically when you use a statement like:\n",
"\n",
" myTN = TreeNode('My name is Joe')\n",
"```python\n",
"myTN = TreeNode('My name is Joe')\n",
"```\n",
" \n",
"The first argument, conventionally called 'self', refers to the specific instance of the object, and is required for all instance methods; it is automatically filled-in when methods are called using 'dot' notation:\n",
"\n",
" myTN.value()\n",
"```python\n",
"myTN.value()\n",
"```\n",
"\n",
"Notice that the multi-line comment following the class definition will become the classes \"Doc-String\".\n",
"Notice that the multi-line comment following the class definition will become the class's \"Doc-String\".\n",
"\n",
"Instances of above class have five properties: **name, left, right, parent** and **myValue**. We may also think of instances of the class as *containing* these five objects.\n",
"\n",
"The instances also has one *user* method: **value()** and one *internal* method: **\\_\\_init\\_\\_() **"
"The instances also has one *user* method: `value()` and one *internal* method: `__init__()`"
]
},
{
Expand Down Expand Up @@ -110,7 +114,7 @@
"name": "stdout",
"output_type": "stream",
"text": [
"<__main__.TreeNode object at 0x0000026E3E88F048>\n"
"<__main__.TreeNode object at 0x000002092B848608>\n"
]
}
],
Expand All @@ -126,8 +130,8 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"Not particuarly usefull! Let's fix that.\n",
"\\_\\_str\\_\\_ is the protocol for defining how an object will print or be represented as a string.\n",
"Not particularly useful! Let's fix that.\n",
"`__str__` is the protocol for defining how an object will print or be represented as a string.\n",
"Let's redefine our class..."
]
},
Expand Down Expand Up @@ -167,7 +171,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"Notice that we are using \\_\\_str\\_\\_ recursively as as the str function calls \\_\\_str\\_\\_ -- we we frequently make use of recursive functions when dealing with trees"
"Notice that we are using `__str__` recursively as as the `str` function calls `__str__` -- we we frequently make use of recursive functions when dealing with trees"
]
},
{
Expand All @@ -194,7 +198,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"The value method is really acting as an alias for the myValue property, it would be nice if we could just access it like any other property. We can do this with the <b>@property</b> decorator. A decorator is a function that modifies the behaviour of the method or function that follows it. In this case it allow us to access the *value* method as if it was a property rather than a method, e.g. <b>nd1.value</b> instead of <b>nd1.value()</b>"
"The `value` method is really acting as an alias for the `myValue` property, it would be nice if we could just access it like any other property. We can do this with the `@property` decorator. A decorator is a function that modifies the behaviour of the method or function that follows it. In this case it allow us to access the `value` method as if it was a property rather than a method, e.g. `nd1.value` instead of `nd1.value()`"
]
},
{
Expand Down Expand Up @@ -266,18 +270,13 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"Property methods are usefull for properties that are calculated 'on-the-fly'; we will see later that they can also be used for data validation."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Property methods are useful for properties that are calculated 'on-the-fly'; we will see later that they can also be used for data validation.\n",
"\n",
"Notice that we are unable to assign a value using the name.\n",
"\n",
"We will see how to overcome this later.\n",
"\n",
"Although we can still use myValue"
"Although we can still use `myValue`"
]
},
{
Expand Down Expand Up @@ -393,7 +392,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"Let's see what's going on..? The **dir** function will list an object's properties and methods (including those inherited from the superclass<sup>2</sup>)\n",
"Let's see what's going on..? The `dir` function will list an object's properties and methods (including those inherited from the superclass<sup>2</sup>)\n",
"\n",
"2: Explained more fully later."
]
Expand Down Expand Up @@ -447,22 +446,14 @@
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This is an example of Python's _name mangling_, in this case it is being used to hide the private property. The upshot is that you don't really wan't to mess with private properties."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The fact that in Python you can create a new property on-the-fly outside of the class definition (also works for methods) is called _Monkey Patching_."
]
},
{
"cell_type": "markdown",
"metadata": {},
"metadata": {
"tags": []
},
"source": [
"This is an example of Python's _name mangling_, in this case it is being used to hide the private property. The upshot is that you don't really want to mess with private properties.\n",
"\n",
"The fact that in Python you can create a new property on-the-fly outside of the class definition (also works for methods) is called _Monkey Patching_.\n",
"\n",
"Now let us see how can modify the value property so that we can update it."
]
},
Expand Down Expand Up @@ -548,14 +539,18 @@
"\n",
"Perhaps a more useful use of the setter decorator is to enforce a *side effect*. Consider the need to set the parent property, currently we might do something like:\n",
"\n",
" p = TreeNode('P')\n",
" p.left = TreeNode('LC')\n",
" p.left.parent = p\n",
"```python\n",
"p = TreeNode('P')\n",
"p.left = TreeNode('LC')\n",
"p.left.parent = p\n",
"```\n",
" \n",
"although we can shorten this to:\n",
"\n",
" p = TreeNode('P')\n",
" p.left = TreeNode('LC',p)\n",
"```python\n",
"p = TreeNode('P')\n",
"p.left = TreeNode('LC',p)\n",
"```\n",
" \n",
"It is possible that the user may forget to set the parent property. We can fix this as follows:"
]
Expand Down Expand Up @@ -656,7 +651,7 @@
},
{
"cell_type": "code",
"execution_count": 31,
"execution_count": 18,
"metadata": {},
"outputs": [],
"source": [
Expand All @@ -674,7 +669,7 @@
},
{
"cell_type": "code",
"execution_count": 34,
"execution_count": 19,
"metadata": {},
"outputs": [
{
Expand Down Expand Up @@ -737,10 +732,10 @@
"</svg>\r\n"
],
"text/plain": [
"<graphviz.dot.Digraph at 0x26e40401f48>"
"<graphviz.dot.Digraph at 0x2092b7accc8>"
]
},
"execution_count": 34,
"execution_count": 19,
"metadata": {},
"output_type": "execute_result"
}
Expand All @@ -753,33 +748,18 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"## Leveraging GraphViz to render our custom trees"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Notice that GraphViz uses the _name_ as a unique identifier; we will therefore implement a unique identifier for each node. We will use a _class property_ to keep track of the UIDs created. Similarly, we can have <b>@classmethod</b> which we have used to fetch the next UID. Notice that the class method's first parameter is *cls* rather than *self* - it is a reference to this class rather than a specific instance."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We generate the graph to be plotted using a recursive helper function which for illustration has been defined as a <b>@staticmethod</b>. A static method is one that does not depend on the instance i.e. it does not require _self_. In this case we could have just used a normal method..."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Leveraging GraphViz to render our custom trees\n",
"\n",
"Notice that GraphViz uses the _name_ as a unique identifier; we will therefore implement a unique identifier for each node. We will use a _class property_ to keep track of the UIDs created. Similarly, we can have `@classmethod` which we have used to fetch the next UID. Notice that the class method's first parameter is `cls` rather than `self` - it is a reference to this class rather than a specific instance.\n",
"\n",
"We generate the graph to be plotted using a recursive helper function which for illustration has been defined as a `@staticmethod`. A static method is one that does not depend on the instance i.e. it does not require `_self_`. In this case we could have just used a normal method...\n",
"\n",
"Code adapted from: https://h1ros.github.io/posts/introduction-to-graphviz-in-jupyter-notebook/"
]
},
{
"cell_type": "code",
"execution_count": 35,
"execution_count": 20,
"metadata": {},
"outputs": [],
"source": [
Expand Down Expand Up @@ -880,7 +860,7 @@
},
{
"cell_type": "code",
"execution_count": 36,
"execution_count": 21,
"metadata": {},
"outputs": [
{
Expand Down Expand Up @@ -955,10 +935,10 @@
"</svg>\r\n"
],
"text/plain": [
"<graphviz.dot.Digraph at 0x26e3fd09dc8>"
"<graphviz.dot.Digraph at 0x2092b8487c8>"
]
},
"execution_count": 36,
"execution_count": 21,
"metadata": {},
"output_type": "execute_result"
}
Expand All @@ -981,7 +961,7 @@
},
{
"cell_type": "code",
"execution_count": 37,
"execution_count": 22,
"metadata": {},
"outputs": [
{
Expand All @@ -990,7 +970,7 @@
"6"
]
},
"execution_count": 37,
"execution_count": 22,
"metadata": {},
"output_type": "execute_result"
}
Expand All @@ -1001,7 +981,7 @@
},
{
"cell_type": "code",
"execution_count": 38,
"execution_count": 23,
"metadata": {},
"outputs": [
{
Expand All @@ -1010,7 +990,7 @@
"6"
]
},
"execution_count": 38,
"execution_count": 23,
"metadata": {},
"output_type": "execute_result"
}
Expand All @@ -1023,7 +1003,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"For simplicity, we draw the links as single arrows, although in reality they should be double arrows [because of the link from child to parent via the parent property]"
"For simplicity, we draw the links as single arrows, although in reality they should be double arrows because of the link from *child* to *parent* via the `parent` property."
]
},
{
Expand Down
Loading