{ "cells": [ { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Python Classes and Object-Oriented Programming\n", "\n", "Below is a class definition named `Shape()`. It stores the data attribute `shape` which is just a string. The only member function implmented in this class is the special `__str__` function which returns the string `I am a shape` when called on an object instantiated from the class `Shape()`." ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "collapsed": true }, "outputs": [], "source": [ "class Shape():\n", " \n", " def __init__(self):\n", " self.shape = 'shape'\n", " \n", " def __str__(self):\n", " return \"I am a \" + self.shape" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now we will instantiation the class and store it in an object with the variable name `s`. Then we call the print statement giving `s` as and argument and it automatically runs the `__str__` function and returns its result." ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "I am a shape\n" ] } ], "source": [ "s = Shape()\n", "print(s)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now we will derive a class from `Shape()` called `Polygon()`. A `Polygon()` *is a* `Shape()` and therefore all of the functions defined in `Shape()` will work on an instantiated object of `Polygon()`.\n", "\n", "We will also implement some new functions, not defined in `Shape()` that can computute the perimeter of a polygon and return the number of edges.\n", "\n", "There is also a new data attribute called `side_lengths` which is initialized to `None`. We can't set its exact value yet because we don't have enough information about the polygon, e.g. How many sides it has, but we need to define it in order to define `compute_perimeter()` because it requires `side_lengths` as an argument. Same goes for `get_number_of_sides`." ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "collapsed": true }, "outputs": [], "source": [ "class Polygon(Shape):\n", " \n", " def __init__(self):\n", " self.shape = 'polygon'\n", " self.side_lengths = None\n", " \n", " def compute_perimeter(self):\n", " return sum(self.side_lengths)\n", " \n", " def get_number_of_edges(self):\n", " return len(self.side_lengths)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now we can instantiation a `Polygon()` object called `p` and call `print()` on it. It returns the function call from `__str__` that is *only* defined in `Shape()` because a `Polygon()` *is a* `Shape()`." ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "I am a polygon\n" ] } ], "source": [ "p = Polygon()\n", "print(p)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can now derived another class from `Polygon()`, this time we are specialized enough that we know a `Rectange()` has 4 sides, so we can give a default value for the data attribute `side_length`." ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "class Rectangle(Polygon):\n", " \n", " def __init__(self):\n", " \n", " self.shape = 'rectangle'\n", " self.side_lengths = [1, 1, 1, 1]" ] }, { "cell_type": "markdown", "metadata": { "collapsed": true }, "source": [ "And now we can call `compute_perimeter()` on the object `rect` that was intantiated from `Rectangle()` even though we didn't define the function in the `Rectangle()` class. We can do this because a `Rectangle()` *is a* `Polygon()`." ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "4" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "rect = Rectangle()\n", "rect.compute_perimeter()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Likewise, we can derive a `Triangle()` class from `Polygon()` and it *inherits* the member functions from both `Polygon()` and `Shape()`. Again, a `Triangle()` *is a* `Polygon()` which *is a* `Shape()`." ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [], "source": [ "class Triangle(Polygon):\n", " \n", " def __init__(self):\n", " self.shape = 'triangle'\n", " self.side_lengths = [2, 2, 2] " ] }, { "cell_type": "markdown", "metadata": { "collapsed": true }, "source": [ "Examples of calling functions on the object `t` instantiated from `Triangle()`." ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "6" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "t = Triangle()\n", "t.compute_perimeter()" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "3" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "t.get_number_of_edges()" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "I am a triangle\n" ] } ], "source": [ "print(t)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Everything in Python is an object. Including the lists we've already been using. This might help you understand the `.sort()` function a little better now." ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[4, 20, 100]" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x = [20, 4, 100]\n", "x.sort()\n", "x" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "You can also define classes that take arguments similar to the way regular functions do. Both classes and functions that are members of a class must use `self` as thier first argument. After that you can use arguments as you normally would, including default arguments and variable arguments." ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "collapsed": true }, "outputs": [], "source": [ "class Car():\n", " \n", " def __init__(self, number_of_doors=2):\n", " \n", " self.number_of_doors = number_of_doors\n", " \n", " def __str__(self):\n", " \n", " if self.number_of_doors == 2:\n", " return \"I am a coupe.\"\n", " if self.number_of_doors == 4:\n", " return \"I am a sedan.\"\n", " else:\n", " return \"I don't know what kind of car I am.\"\n", " " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "An example of instantiating the `Car()` class with different arguments that alter it's behavior." ] }, { "cell_type": "code", "execution_count": 13, "metadata": { "collapsed": true }, "outputs": [], "source": [ "c = Car()" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "I am a coupe.\n" ] } ], "source": [ "print(c)" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "I am a sedan.\n" ] } ], "source": [ "s = Car(4)\n", "print(s)" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "I don't know what kind of car I am.\n" ] } ], "source": [ "s = Car(3)\n", "print(s)" ] } ], "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.6.2" } }, "nbformat": 4, "nbformat_minor": 2 }