{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "\n", "
\n", " \n", " \"QuantEcon\"\n", " \n", "
" ] }, { "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 }