"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# OOP I: Introduction to Object Oriented Programming"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Contents\n",
"\n",
"- [OOP I: Introduction to Object Oriented Programming](#OOP-I:-Introduction-to-Object-Oriented-Programming) \n",
" - [Overview](#Overview) \n",
" - [Objects](#Objects) \n",
" - [Summary](#Summary) "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Overview\n",
"\n",
"[OOP](https://en.wikipedia.org/wiki/Object-oriented_programming) is one of the major paradigms in programming.\n",
"\n",
"The traditional programming paradigm (think Fortran, C, MATLAB, etc.) is called *procedural*.\n",
"\n",
"It works as follows\n",
"\n",
"- The program has a state corresponding to the values of its variables. \n",
"- Functions are called to act on these data. \n",
"- Data are passed back and forth via function calls. \n",
"\n",
"\n",
"In contrast, in the OOP paradigm\n",
"\n",
"- data and functions are “bundled together” into “objects” \n",
"\n",
"\n",
"(Functions in this context are referred to as **methods**)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Python and OOP\n",
"\n",
"Python is a pragmatic language that blends object-oriented and procedural styles, rather than taking a purist approach.\n",
"\n",
"However, at a foundational level, Python *is* object-oriented.\n",
"\n",
"In particular, in Python, *everything is an object*.\n",
"\n",
"In this lecture, we explain what that statement means and why it matters."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Objects\n",
"\n",
"\n",
"\n",
"In Python, an *object* is a collection of data and instructions held in computer memory that consists of\n",
"\n",
"1. a type \n",
"1. a unique identity \n",
"1. data (i.e., content) \n",
"1. methods \n",
"\n",
"\n",
"These concepts are defined and discussed sequentially below.\n",
"\n",
"\n",
""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Type\n",
"\n",
"\n",
"\n",
"Python provides for different types of objects, to accommodate different categories of data.\n",
"\n",
"For example"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"hide-output": false
},
"outputs": [],
"source": [
"s = 'This is a string'\n",
"type(s)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"hide-output": false
},
"outputs": [],
"source": [
"x = 42 # Now let's create an integer\n",
"type(x)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The type of an object matters for many expressions.\n",
"\n",
"For example, the addition operator between two strings means concatenation"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"hide-output": false
},
"outputs": [],
"source": [
"'300' + 'cc'"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"On the other hand, between two numbers it means ordinary addition"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"hide-output": false
},
"outputs": [],
"source": [
"300 + 400"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Consider the following expression"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"hide-output": false
},
"outputs": [],
"source": [
"'300' + 400"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Here we are mixing types, and it’s unclear to Python whether the user wants to\n",
"\n",
"- convert `'300'` to an integer and then add it to `400`, or \n",
"- convert `400` to string and then concatenate it with `'300'` \n",
"\n",
"\n",
"Some languages might try to guess but Python is *strongly typed*\n",
"\n",
"- Type is important, and implicit type conversion is rare. \n",
"- Python will respond instead by raising a `TypeError`. \n",
"\n",
"\n",
"To avoid the error, you need to clarify by changing the relevant type.\n",
"\n",
"For example,"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"hide-output": false
},
"outputs": [],
"source": [
"int('300') + 400 # To add as numbers, change the string to an integer"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n",
""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Identity\n",
"\n",
"\n",
"\n",
"In Python, each object has a unique identifier, which helps Python (and us) keep track of the object.\n",
"\n",
"The identity of an object can be obtained via the `id()` function"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"hide-output": false
},
"outputs": [],
"source": [
"y = 2.5\n",
"z = 2.5\n",
"id(y)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"hide-output": false
},
"outputs": [],
"source": [
"id(z)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"In this example, `y` and `z` happen to have the same value (i.e., `2.5`), but they are not the same object.\n",
"\n",
"The identity of an object is in fact just the address of the object in memory."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Object Content: Data and Attributes\n",
"\n",
"\n",
"\n",
"If we set `x = 42` then we create an object of type `int` that contains\n",
"the data `42`.\n",
"\n",
"In fact, it contains more, as the following example shows"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"hide-output": false
},
"outputs": [],
"source": [
"x = 42\n",
"x"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"hide-output": false
},
"outputs": [],
"source": [
"x.imag"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"hide-output": false
},
"outputs": [],
"source": [
"x.__class__"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"When Python creates this integer object, it stores with it various auxiliary information, such as the imaginary part, and the type.\n",
"\n",
"Any name following a dot is called an *attribute* of the object to the left of the dot.\n",
"\n",
"- e.g.,`imag` and `__class__` are attributes of `x`. \n",
"\n",
"\n",
"We see from this example that objects have attributes that contain auxiliary information.\n",
"\n",
"They also have attributes that act like functions, called *methods*.\n",
"\n",
"These attributes are important, so let’s discuss them in-depth.\n",
"\n",
"\n",
""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Methods\n",
"\n",
"\n",
"\n",
"Methods are *functions that are bundled with objects*.\n",
"\n",
"Formally, methods are attributes of objects that are callable (i.e., can be called as functions)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"hide-output": false
},
"outputs": [],
"source": [
"x = ['foo', 'bar']\n",
"callable(x.append)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"hide-output": false
},
"outputs": [],
"source": [
"callable(x.__doc__)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Methods typically act on the data contained in the object they belong to, or combine that data with other data"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"hide-output": false
},
"outputs": [],
"source": [
"x = ['a', 'b']\n",
"x.append('c')\n",
"s = 'This is a string'\n",
"s.upper()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"hide-output": false
},
"outputs": [],
"source": [
"s.lower()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"hide-output": false
},
"outputs": [],
"source": [
"s.replace('This', 'That')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"A great deal of Python functionality is organized around method calls.\n",
"\n",
"For example, consider the following piece of code"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"hide-output": false
},
"outputs": [],
"source": [
"x = ['a', 'b']\n",
"x[0] = 'aa' # Item assignment using square bracket notation\n",
"x"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"It doesn’t look like there are any methods used here, but in fact the square bracket assignment notation is just a convenient interface to a method call.\n",
"\n",
"What actually happens is that Python calls the `__setitem__` method, as follows"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"hide-output": false
},
"outputs": [],
"source": [
"x = ['a', 'b']\n",
"x.__setitem__(0, 'aa') # Equivalent to x[0] = 'aa'\n",
"x"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"(If you wanted to you could modify the `__setitem__` method, so that square bracket assignment does something totally different)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Summary\n",
"\n",
"In Python, *everything in memory is treated as an object*.\n",
"\n",
"This includes not just lists, strings, etc., but also less obvious things, such as\n",
"\n",
"- functions (once they have been read into memory) \n",
"- modules (ditto) \n",
"- files opened for reading or writing \n",
"- integers, etc. \n",
"\n",
"\n",
"Consider, for example, functions.\n",
"\n",
"When Python reads a function definition, it creates a **function object** and stores it in memory.\n",
"\n",
"The following code illustrates"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"hide-output": false
},
"outputs": [],
"source": [
"def f(x): return x**2\n",
"f"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"hide-output": false
},
"outputs": [],
"source": [
"type(f)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"hide-output": false
},
"outputs": [],
"source": [
"id(f)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"hide-output": false
},
"outputs": [],
"source": [
"f.__name__"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We can see that `f` has type, identity, attributes and so on—just like any other object.\n",
"\n",
"It also has methods.\n",
"\n",
"One example is the `__call__` method, which just evaluates the function"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"hide-output": false
},
"outputs": [],
"source": [
"f.__call__(3)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Another is the `__dir__` method, which returns a list of attributes.\n",
"\n",
"Modules loaded into memory are also treated as objects"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"hide-output": false
},
"outputs": [],
"source": [
"import math\n",
"\n",
"id(math)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This uniform treatment of data in Python (everything is an object) helps keep the language simple and consistent."
]
}
],
"metadata": {
"date": 1614096163.6008697,
"filename": "oop_intro.md",
"kernelspec": {
"display_name": "Python",
"language": "python3",
"name": "python3"
},
"title": "OOP I: Introduction to Object Oriented Programming"
},
"nbformat": 4,
"nbformat_minor": 4
}