{ "cells": [ { "cell_type": "raw", "metadata": {}, "source": [ "---\n", "title: Class Methods\n", "file_title: class_methods\n", "---" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Defining a Point With Cartesian Coordinates\n", "\n", "A point can be described by an $x$, $y$ coordinate pair (in 2D). In Python, a simple class can be created to manage a `Point`. The `__init__` class function, or \"method\" takes in a reference to the newly created object called `self` and the $x$ and $y$ coordinate. For printing a readable output the `__repr__` method is created which simply returns a `string` that represents the point." ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "class Point:\n", " \n", " def __init__(self, x, y):\n", " self.x = x\n", " self.y = y\n", " \n", " def __repr__(self):\n", " return f'({self.x}, {self.y})'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can test this class by creating, or *instanciating* the class by calling it with an $x$, $y$ coordinate pair. This will simply print the point since we implemented the `__repr__` function." ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(1, 1)" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Point(1, 1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Defining a Point With Polar Coordinates\n", "\n", "Points are sometimes best described in terms of *polar coordinates* instead of Cartesian coordinates. We could create an entirely new class that implements an `__init__` method that takes in a radius and angle but instead of creating an independent `Point` class, what we can do is create a \"class method\" that will translate the polar description to a Cartesian description and then create the `Point` object.\n", "\n", "\\begin{equation}\n", "\\mathbf{x} = \\{x, y\\} = \\{R\\cos(\\theta), R\\sin(\\theta)\\}\n", "\\end{equation}\n", "\n", "A class method is defined just like all other methods, but the `@classmethod` decorator is added above the method creation, and the implicit argument is the reference to the class, `cls`, instead of a particular instance of the class, `self`. The method then returns a new `Point` by calling `cls`. This calls the original `__init__` method but with the polar coordinates translated to Cartesian coordinates." ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "\n", "class Point:\n", " \n", " def __init__(self, x, y):\n", " self.x = x\n", " self.y = y\n", " \n", " @classmethod\n", " def polar(cls, R, theta):\n", " x = R*np.cos(theta)\n", " y = R*np.sin(theta)\n", " return cls(x, y)\n", " \n", " def __repr__(self):\n", " return f'({self.x}, {self.y})'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now instead of having users always make the translation within their own code, they can simply call the class method with the polar coodinates. This avoids repetition and helps create more maintainable code." ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(1.0, 0.0)" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Point.polar(1, 0)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In other languages this is known as an *alternative constructor*. In Python, there is no way to create multiple constructors and instead these class methods are used to translate input to create the object with the *default constructor*. This is a useful idea to use whenever there are multiple descriptions for the same object, in this case, polar vs. cartesian coordinates." ] } ], "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.10" } }, "nbformat": 4, "nbformat_minor": 2 }