summaryrefslogtreecommitdiff
path: root/notebooks/python/python_oo.ipynb
blob: 0b33a09ff26606a1040ef9ecc5f41fd6f70d8d47 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "2612fc97-1e84-4cc1-bd55-4cc58dbd5074",
   "metadata": {},
   "source": [
    "# Introduction to object-oriented programming in Python\n",
    "\n",
    "Simeon Simeonov @ Statnett"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "84139fa9-733e-4871-a2f9-920f6e7c4911",
   "metadata": {},
   "source": [
    "# Goals\n",
    "\n",
    "- present the Python programming language in a different way than [https://docs.python.org](https://docs.python.org)\n",
    "\n",
    "- avoid information overload\n",
    "\n",
    "- use examples and interaction rather than documents and slides\n",
    "\n",
    "\n",
    "## Target audience\n",
    "\n",
    "- beginner Python programmers\n",
    "\n",
    "- analysts using Python as a tool"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d6d3d0e7-c1d5-4119-940e-0f94ee7542ec",
   "metadata": {},
   "source": [
    "# What is object-oriented programming?\n",
    "\n",
    "Object-oriented programming does **not** mean using an object-oriented programming language.\n",
    "\n",
    "It is rather a programming paradigm based on the concept of object, as well as on some general principles and best practices aiming at:\n",
    "\n",
    "- improving readability\n",
    "\n",
    "- improving re-usability\n",
    "\n",
    "- improving modularity\n",
    "\n",
    "- providing foundation for a more intuitive design"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ad19da5c-3c21-4130-9225-d8f7cb2a7f40",
   "metadata": {},
   "source": [
    "# General principles\n",
    "\n",
    "The following four concepts / principles are presented in most object-oriented programming books:\n",
    "\n",
    "- separate and hide \"private\" details from the outside world and / or child (inheriting) functionality (*encapsulation*) - supports *separation of concerns*\n",
    "\n",
    "- separate the interface from its implementation (*abstraction*)\n",
    "\n",
    "- inherit and extend / adapt existing functionality, through \"is-a\" relationship hierarchy (*inheritance*)\n",
    "\n",
    "- execute different code / functionality based on the object's place in the hierarchy (polymorphism)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "22b2bf7e-764b-44c8-a9fd-83733319fc6e",
   "metadata": {},
   "source": [
    "# Building blocks and definitions\n",
    "\n",
    "**Note:** \"Lacking universally accepted terminology to talk about classes, I will make occasional use of Smalltalk and C++ terms.\" - The Python tutorial [https://docs.python.org](https://docs.python.org)\n",
    "\n",
    "When talking about object-oriented programming, the following building blocks are involved:\n",
    "\n",
    "- class - a blueprint / template for creating objects\n",
    "\n",
    "- object - an instance of a class that may contain its own attributes as well as references to its class' attributes\n",
    "\n",
    "- attribute - variable, property, function defined in the class and present in its instances\n",
    "\n",
    "- class variable - attribute of which a single copy exists, regardless of how many instances of the class exist\n",
    "\n",
    "- object / instance variable - attribute for which each instantiated object of the class has a separate copy, or instance\n",
    "\n",
    "- method - member function - function that is an attribute"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9e15c843-f65b-4bd3-a536-e0217b3947f8",
   "metadata": {},
   "source": [
    "# The object-oriented world of Python\n",
    "\n",
    "Some additional concepts and definitions are introduced in Python, as well as in some other programming languages:\n",
    "\n",
    "- metaclass - a class whose instances are classes\n",
    "\n",
    "- property - attribute that provides a flexible mechanism to read, write, or compute the value of a \"private\" attribute\n",
    "\n",
    "- type - old C object-oriented term, now (in Python 3) considered to be the same as class\n",
    "\n",
    "As is true for modules, classes partake of the dynamic nature of Python: they are created at runtime, and can be modified further after creation.\n",
    "\n",
    "Each object in Python has an ID - an integer which is guaranteed to be unique and constant for this object during its lifetime.\n",
    "Two objects with non-overlapping lifetimes may have the same *id()* value. In *CPython* this is the address of the object in memory.\n",
    "\n",
    "Python has automatic memory management using reference counting. When an object no longer has\n",
    "any references, the garbage collector kicks inn and removes the object from memory."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d647b1ad-948d-495d-bb30-15761b806354",
   "metadata": {},
   "source": [
    "# Example1\n",
    "\n",
    "We will create and extend classes for representing points and vectors in 2D space"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "391e816e-c53b-454b-9e9f-3587234f1fea",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2:8\n",
      "2:8\n",
      "2\n",
      "2\n"
     ]
    },
    {
     "ename": "AttributeError",
     "evalue": "'Point' object has no attribute '__y'",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mAttributeError\u001b[0m                            Traceback (most recent call last)",
      "Cell \u001b[0;32mIn [7], line 69\u001b[0m\n\u001b[1;32m     66\u001b[0m \u001b[38;5;66;03m# we \"should not\" be accessing private and protected attributes directly\u001b[39;00m\n\u001b[1;32m     67\u001b[0m \u001b[38;5;28mprint\u001b[39m(my_first_point\u001b[38;5;241m.\u001b[39m_x)\n\u001b[0;32m---> 69\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[43mmy_first_point\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m__y\u001b[49m)\n",
      "\u001b[0;31mAttributeError\u001b[0m: 'Point' object has no attribute '__y'"
     ]
    }
   ],
   "source": [
    "class Point:\n",
    "    \"\"\"Basic class for representing points in 2D space\"\"\"\n",
    "\n",
    "    def __init__(self, x: int, y: int):\n",
    "        \"\"\"\n",
    "        Called after the instance has been created (by __new__()), but before\n",
    "        it is returned to the caller. The arguments are those passed to the\n",
    "        class constructor expression.\n",
    "        \n",
    "        If a base class has an __init__() method, the derived class’s\n",
    "        __init__() method, if any, must explicitly call it to ensure proper\n",
    "        initialization of the base class part of the instance;\n",
    "        for example: super().__init__([args...]).\n",
    "        \"\"\"\n",
    "        self._x = x  # _ indicates \"protected\" attribute\n",
    "        self.__y = y  # not a typo: __ indicates \"private\" attribute\n",
    "\n",
    "    def __repr__(self):\n",
    "        \"\"\"\n",
    "        Called by the repr() built-in function to compute the “official”\n",
    "        string representation of an object. If at all possible, this should\n",
    "        look like a valid Python expression that could be used to recreate an\n",
    "        object with the same value (given an appropriate environment). If this\n",
    "        is not possible, a string of the form <...some useful description...>\n",
    "        should be returned. The return value must be a string object.\n",
    "        \n",
    "        If a class defines __repr__() but not __str__(), then __repr__() is\n",
    "        also used when an “informal” string representation of instances of\n",
    "        that class is required. This is typically used for debugging, so it is\n",
    "        important that the representation is information-rich and unambiguous.\n",
    "        \"\"\"\n",
    "        return f\"<Point(x={self._x!r}, y={self.__y!r})>\"\n",
    "\n",
    "    def __str__(self):\n",
    "        \"\"\"\n",
    "        Called by str(object) and the built-in functions format() and print()\n",
    "        to compute the “informal” or nicely printable string representation of\n",
    "        an object. The return value must be a string object.\n",
    "\n",
    "        This method differs from object.__repr__() in that there is no\n",
    "        expectation that __str__() return a valid Python expression: a more\n",
    "        convenient or concise representation can be used.\n",
    "\n",
    "        The default implementation defined by the built-in type object calls\n",
    "        object.__repr__().\n",
    "        \"\"\"\n",
    "        return f\"{self._x}:{self.__y}\"\n",
    "\n",
    "    @property\n",
    "    def x(self) -> int:\n",
    "        \"\"\"getter property x\"\"\"\n",
    "        return self._x\n",
    "\n",
    "    @property\n",
    "    def y(self) -> int:\n",
    "        \"\"\"getter property y\"\"\"\n",
    "        return self.__y\n",
    "\n",
    "\n",
    "my_first_point = Point(2, 8)\n",
    "\n",
    "print(f\"{my_first_point}\")\n",
    "print(f\"{my_first_point}\")\n",
    "print(my_first_point.x)\n",
    "\n",
    "# we \"should not\" be accessing private and protected attributes directly\n",
    "print(my_first_point._x)\n",
    "\n",
    "print(my_first_point.__y)  # will not work\n",
    "# Out: AttributeError: 'Point' object has no attribute '__y'\n",
    "\n",
    "# will work, but should not be used by a sane programmer:\n",
    "# print(my_first_point._Point__y)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e82feefb-025d-4cbb-a8ac-ddc3cc01269c",
   "metadata": {},
   "outputs": [],
   "source": [
    "class Vector:\n",
    "    \"\"\"Basic class for representing vectors in 2D space\"\"\"\n",
    "\n",
    "    def __init__(self, start: Point, end: Point):\n",
    "        self._start = start\n",
    "        self._end = end\n",
    "\n",
    "    def __str__(self):\n",
    "        return f\"{self._start} -> {self._end}\"\n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "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.8.10"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}