{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Classes and Objects II\n", "\n", "- [Download the lecture notes](https://philchodrow.github.io/PIC16A/content/object_oriented_programming/classes_and_objects_II.ipynb). \n", "\n", "In these notes, we'll further develop our skills with object-oriented programming. Our primary focus will be on the use of **magic methods** to perform custom operations on our objects. \n", "\n", "## Example: Vectors\n", "\n", "Let's implement a `Vector` class. `Vector`s should admit operations like addition, subtraction, and scalar multiplication. Perhaps surprisingly, Python doesn't really support this natively. For example: " ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(1, 2, 3, 4)" ] }, "execution_count": 1, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# (1, 2) + (3, 4) = (4, 6)\n", "\n", "(1, 2) + (3, 4)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "So, let's do it ourselves! We'll focus on vectors with just two dimensions. We'll soon introduce the `numpy` module for working with vectors of arbitrary dimensions. " ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "class Vector:\n", " \"\"\"\n", " Class for 2-dimensional vectors\n", " Supports standard vector operations, including scalar multiplication and vector addition. \n", " \"\"\"\n", " def __init__(self, x, y):\n", " self.x = x\n", " self.y = y\n", " \n", " def scalar_multiply(self, c):\n", " \"\"\"\n", " Return a Vector with components multiplied by c\n", " \"\"\"\n", " return(Vector(c*self.x, c*self.y)) " ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(2, 4)" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "v = Vector(1, 2)\n", "u = v.scalar_multiply(2)\n", "u.x, u.y" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "So far so good, but it's not all that easy to actually view the result of the scalar multiplication. For example: " ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "class Vector:\n", " \"\"\"\n", " Class for 2-dimensional vectors\n", " Supports standard vector operations, including scalar multiplication and vector addition. \n", " \"\"\"\n", " def __init__(self, x, y):\n", " self.x = x\n", " self.y = y\n", " \n", " def scalar_multiply(self, c):\n", " \"\"\"\n", " Return a Vector with components multiplied by c\n", " \"\"\"\n", " return(Vector(c*self.x, c*self.y)) \n", " \n", " def __str__(self):\n", " return(\"Vector(\" + str(self.x) + \",\" + str(self.y) + \")\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This motivates us to add a method for representing `v` nicely as a string. The `__str__` *magic method* does this for us. " ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Vector(1,2)\n" ] } ], "source": [ "v = Vector(1,2)\n", "print(v)\n", "# ---" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Vector(2,4)\n" ] } ], "source": [ "print(v.scalar_multiply(2))\n", "# --- " ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [], "source": [ "class Vector:\n", " \"\"\"\n", " Class for 2-dimensional vectors\n", " Supports standard vector operations, including scalar multiplication and vector addition. \n", " \"\"\"\n", " def __init__(self, x, y):\n", " self.x = x\n", " self.y = y\n", " \n", " def scalar_multiply(self, c):\n", " \"\"\"\n", " Return a Vector with components multiplied by c\n", " \"\"\"\n", " return(Vector(c*self.x, c*self.y)) \n", " \n", " def __str__(self):\n", " return(\"Vector(\" + str(self.x) + \",\" + str(self.y) + \")\")\n", " \n", " def __add__(self, other):\n", " return(Vector(self.x + other.x, self.y + other.y))\n", " \n", " def __sub__(self, other):\n", " return(Vector(self.x - other.x, self.y - other.y))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can also add useful *binary operations*, like addition. The \"magic\" in \"magic method\" refers to the fact that Python will automatically use these methods when interpreting symbols like `+` and `*`. Often times, magic methods are extremely obvious to implement, and in this case it's ok not to document them. \n", "\n", "There are MANY magic methods -- check out [this blog post](https://rszalski.github.io/magicmethods/) for a complete list. For now, let's just implement addition and subtraction. " ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Vector(2,3)\n", "Vector(0,1)\n" ] } ], "source": [ "u = Vector(1, 2)\n", "v = Vector(1, 1)\n", "print(u+v)\n", "print(u-v)\n", "# ---" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "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.3" } }, "nbformat": 4, "nbformat_minor": 4 }