{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### <p style=\"text-align: right;\"> &#9989; **Put your name here** </p>\n",
    "#### <p style=\"text-align: right;\"> &#9989; Put your group member names here</p>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Day 15 In-Class Assignment: More OOP\n",
    "    "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Agenda for today's class\n",
    "\n",
    "</p>\n",
    "\n",
    "1. More review of OOP in Python.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 1 More about methods\n",
    "\n",
    "Still working with our `Point` class below"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Point(object):\n",
    "   def __init__(self,x=0,y=0):\n",
    "        self.x_coord = x\n",
    "        self.y_coord = y\n",
    "   def translate(self,x=0,y=0): \n",
    "        self.x_coord += x  \n",
    "        self.y_coord += y\n",
    "   def print_point(self):\n",
    "        print(\"({:d},{:d})\".format(self.x_coord, self.y_coord))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<img src=\"https://i.ibb.co/LvQXwGz/point1.png\" alt=\"point1\" border=\"0\">"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`self` is the first parameter of every method. You could give that parameter a different name but **real** Python programmers always call that first parameter `self`. Every method always has at least one parameter, the first parameter, `self`\n",
    "\n",
    "If the attribute we are working with is a **method** (a function attribute) then the goal is to run/invoke/execute that method. In a dot call, the lhs is the name of the instance and the rhs is the method name. Python automatically passes the lhs instance to the first parameter of the rhs method, which we call `self`, and then other parameters as required. \n",
    "\n",
    "<img src=\"https://i.ibb.co/0ckf5FV/dotCall.png\" alt=\"dotCall\" border=\"0\">"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Python *automatically* associates `self` with the calling instance. In this way, we can apply a method to the lhs  instance making the calls: the calling instance: the one that gets bound to `self`.\n",
    "\n",
    "In the method itself, if we want to access data attributes of the calling/lhs instance, we can make a dot call on the `self` parameter. \n",
    "\n",
    "In the `translate` method, when we want to use `x_coord` we  specify the instance it is associated with. In the call (`p0` above), `self` is bound to `p0`. In the method we talk about `self.x_coord` because we want to use the `x_coord` associated with the calling instance. In this way every calling instance is bound to `self` and every reference we make in the method is to the calling instance (in this case `p0`)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "my_point = Point(x=100, y=200)\n",
    "my_point.translate(2,3)\n",
    "my_point.print_point()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# example\n",
    "\n",
    "class SomeClass (object):\n",
    "    def some_method(self, parameter2):\n",
    "        return self.value + parameter2\n",
    "\n",
    "my_instance = SomeClass()\n",
    "my_instance.value = 27\n",
    "print(my_instance.some_method(2))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Question**: what is the value of `self.value` in `some_method` for the expression `my_instance.some_method(2)`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<font size=8 color=\"#009600\">&#9998;</font> Answer:"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Special Python Method Names\n",
    "Python uses special names, beginning and ending with two underlines, for special tasks. We see these when we use the `dir` function on an instance"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "point_instance = Point(x=100, y=100)\n",
    "print(dir(point_instance))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "One particulary interesting method is called `__init__`. This method is part of construction of a new instance.\n",
    "\n",
    "The problem is this. We can assign data attributes using dot call, such as `my_instance.value = 27` seen above, but it is inconvenient. It is tedious to go through and assign data attributes to each intance every time we make an instance. It would be better to initialize **every** instance the same way. That is where `__init__` comes in.\n",
    "\n",
    "When Python constructs an instance using the constructor call, it performs a set of standard *instance building* operations. It then gives the class designer an opportunity to affect the construction process. If the instance has an associated `__init__` method, then the default instance is passed, via the `self` parameter, to be initialized.\n",
    "\n",
    "If no `__init__` is provided, Python returns a default instance. \n",
    "\n",
    "<img src=\"https://i.ibb.co/25RmN1W/init.png\" alt=\"init\" border=\"0\">\n",
    "\n",
    "If we want to give **each** instance of our class the same data attributes, then this is where we do it, in `__init__`. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Point(object):\n",
    "   def __init__(self,x=0,y=0):\n",
    "        self.x_coord = x\n",
    "        self.y_coord = y\n",
    "   def translate(self,x=0,y=0):    \n",
    "        self.x_coord += x    \n",
    "        self.y_coord += y\n",
    "   def print_point(self):    \n",
    "        print(\"({:d},{:d})\".format(self.x_coord, self.y_coord))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "What does the `Point` `__init__` do? Every instance that is created goes through this method. Every instance is assigned, via dot assignment, an `x_coord` and `y_coord` data attribute. Every Point instance has two coordinates, just as we would want!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "p0 = Point()            # default args, x and y are 0\n",
    "p1 = Point(y=100)       # x default, y assigned 0\n",
    "p2 = Point(x=50, y=50)  # assign both x and y\n",
    "print(p0.x_coord, p1.x_coord, p2.x_coord)  # all run through __init__, all have x_coord attribute"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(dir(p0))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### No return in __init__\n",
    "\n",
    "Because a `__init__` is called in the context of a Python pipeline, a series of operations needed to make an instance, Python deals with the manipulation of the default instance.\n",
    "\n",
    "Therefore, it is illegal to have a `return` in a `__init__`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# example\n",
    "\n",
    "class AnotherClass (object):\n",
    "    def __init__(self, parameter1=25, parameter2=50):\n",
    "        self.value1 = parameter1\n",
    "        self.value2 = parameter2\n",
    "        \n",
    "    def some_method(self, parameter2):\n",
    "        return self.value1 + self.value2 + parameter2\n",
    "\n",
    "my_instance = AnotherClass()  #parameter1 and parmameter2 take defauls\n",
    "print(my_instance.some_method(2))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Question**: In `__init__` what is `self` bound to for the call `my_instance = AnotherClass()`?"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<font size=8 color=\"#009600\">&#9998;</font> Answer:"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 2 A simple example: a Clock Class\n",
    "\n",
    "Let's design our own data type, one to represent time as a clock. Here are some the requirements:\n",
    "\n",
    "- each `Clock` instance will represent the present time in hours, minutes and seconds.\n",
    "    - thus each instance will have three data attributes: `hours`, `minutes` and `seconds`\n",
    "- the default instance will have all attributes set to 0\n",
    "- we need to be able to nicely print a clock instance\n",
    "- we want to be able to add two clock instances, yielding a new clock instance:\n",
    "    - no hour will be greater than 23, no minute or second greater than 59\n",
    "    - we will use clock arithmetic: when a sum is larger than the limit, a carry is added\n",
    "    - as our `Clock` instance has no days represented, there is no carry recorded for hours.\n",
    "\n",
    "We will do this in steps, adding methods as we go. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 2.1 Do nothing version\n",
    "\n",
    "You can make a class that has only a body with the keyword `pass`. That's useful to make the class and see what's in it by default.\n",
    "\n",
    "Make a `Clock` class with only the body `pass`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# your code here"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 2.2 Add a constructor\n",
    "\n",
    "OK, remove the `pass` keyword and now make a constructor:\n",
    "- 3 data attributes: `hour`, `minute`, `second`\n",
    "- name of the constructor is always `__init__`\n",
    "- all thee data attributes have a default value of 0\n",
    "\n",
    "Look at the `Point` class for clues"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# your class code here\n",
    "\n",
    "my_clock = Clock()  # this should work\n",
    "print(my_clock.hours) # should be 0"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 2.3 Smarter constructor\n",
    "\n",
    "It should be the case that values passed into the constructor should be within limits:\n",
    "- seconds 0 to 59\n",
    "- minutes 0 to 59\n",
    "- hours 0 to 23 (let's skip the AM/PM problem and have a 24 hour clock)\n",
    "\n",
    "If a value \"rolls over\" it should be added to the element above. For example:\n",
    "- a value of seconds=60 should add 1 to the minutes element and should itself be set to 0\n",
    "- no rollover for hours (no days in our clock)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# your class code here\n",
    "\n",
    "# test case. The extra second propagates and should make everything 0\n",
    "c = Clock(23,59,60)\n",
    "print(c.hours, c.minutes, c.seconds)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 2.4 Print a clock\n",
    "\n",
    "Let's add another method to our `Clock` class called `print_clock`. It should print a nice representation of a clock."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# your code here\n",
    "\n",
    "my_clock=Clock(10,5,5)\n",
    "my_clock.print_clock()\n",
    "# should be something like \"10:05:05\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "-----\n",
    "### Congratulations, we're done!\n",
    "\n",
    "Now, you just need to submit this assignment by uploading it to the course <a href=\"https://d2l.msu.edu/\">Desire2Learn</a> web page for today's submission folder (Don't forget to add your names in the first cell).\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "&#169; Copyright Michigan State University Board of Trustees"
   ]
  }
 ],
 "metadata": {
  "anaconda-cloud": {},
  "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.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
