{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## <p style=\"text-align: right;\"> &#9989; Put your name here</p>\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Day-15-Preclass Introduction to Classes"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Classes are **data types** just like `dict` or `set` or `tuple` or any of the other data types we have become familiar with. They share two characteristics:\n",
    "\n",
    "- They have some internal structure (data) associated with that class\n",
    "\n",
    "- There are some *methods* which can be used to manipulate this data\n",
    "\n",
    "What is interesting about classes is that **we** can create a new datatype, suitable for whatever problems we wish to solve."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## A Way to Think about Programming\n",
    "Object-Oriented Programming (OOP) uses classes to create a different model of programming. We think of a program more as a set of \"objects we communicate with\", a higher level of abstraction than just code.\n",
    "\n",
    "Imagine how you interact with a car. It is a very complicated piece of machinery, machinery mostly **hidden** from you. However, there are some well defined **interfaces** that allow you to control your car: the accelerator, the brake pedal and steering wheel to name three. \n",
    "\n",
    "The complicated machinery is **encapsulated**, a complicated bundle that has a well-defined way to access the bundle's capabilities.\n",
    "<img src=\"https://i.ibb.co/wh37jw0/start.png\">"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The same is true of objects we work with in Python. We have done the following many times:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "my_list = [1,5,2,4,3,9,7]\n",
    "my_list.sort()\n",
    "print(my_list)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We have an object, a particular list `my_list`, which has some number of data elements. We \"told\" `my_list` to \"sort itself\", and it did. How did that sort occur, what are the details? We don't know. We do know, however, that there is a well-defined interface to lists that does sorting, the `sort` method, and that is if we call it the list gets sorted."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Refactoring\n",
    "Not only is the `sort` method hidden from us, but we only know to do sorting using that method. Imagine that some wise Python programmer comes along and finds a \"better\" (faster, smaller, etc.) way to sort a list. We can change the underlying implementation of the `sort` method without affecting anyone who uses it. As long as the **interface stays the same**, we must use the `sort` method, all programmers of Python lists will be unaffected by an update to the `sort` method.\n",
    "\n",
    "Updating existing code to make it better in some way is called **refactoring**. Refactoring requires the changes do not affect programmers who use the improved modules, and you can see that OOP is a good way to accomplish that."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Class and Instance\n",
    "There are two important concepts we need to get straight right at the start: class and instance. Let's talk cookies!\n",
    "\n",
    "One way to make cookies is to get a **cookie cutter** and use that cutter on a sheet of dough. The cutter cuts out **individual cookies**, each cookie just like the previous. Such a cutter could create an infinite number of such cookies (given enough dough, pun intended)!\n",
    "\n",
    "<img src=\"https://i.ibb.co/rZvWn3q/cookie-Cutter.png\">"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In our OOP world, the **class is the cutter** and the **cookie is the instance**. That is, the class acts as a template for stamping out instances of itself. \n",
    "\n",
    "- what do you do with a class/cutter? Create instances\n",
    "- what do you do with an instance/cookie? All instances of a class have some methods associated with them. You can *decorate* a cookie, *bake* a cookie and, best of all *eat* a cookie.\n",
    "\n",
    "But we would **never** get those two things confused, would we. We don't bake, decorate or eat cutters, only cookies. Each instance is an example of the class, but it is the **instances of the class we do work with**. Classes are for making instances, instances do the work once made."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Question:** Can you restate the difference between an instance and a class? Perhaps an analogy?"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<font size=8 color=\"#009600\">&#9998;</font> Your answer here."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Constructing an Instance\n",
    "So how do we make an instance. We really already know how to do this. Look at the below:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "my_dict = dict([('a',1),('b',2),('c',3)])\n",
    "print(type(my_dict), my_dict)\n",
    "my_tuple = tuple([1,2])\n",
    "print(type(my_tuple), my_tuple)\n",
    "my_set = set('abcde')\n",
    "print(type(my_set), my_set)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Every type has a **constructor**, a function which creates instances of the class. There may be *shortcuts* for each constructor, but every type is guaranteed to have this special function available.\n",
    "\n",
    "The name of the constructor is the **same as the name of the type**, only called as a function. We see above the constructor for an instance of a dictionary is `dict`, is called `dict(args)`. The special function `type` gives the type associated with a name. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Let's make a class"
   ]
  },
  {
   "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\">"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "point_instance = Point()\n",
    "print(type(point_instance))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "What is the constructor called? Same name as the class, `Point`. What type is an instance of `Point`? It is of type `Point`. The class is a **new type** and every instance of the class is of the class `Point`.\n",
    "\n",
    "We create classes, new types, that are convenient for solving problems, **our** problems and perhaps problems that other people we know share. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## The `dir` function\n",
    "The `dir` function can be used to list \"stuff in a class instance\". What is in a `Point` instance?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(dir(point_instance))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "A lot of stuff! Many of the \"things\" have weird names, beginning and ending with two underline characters, such as `__str__` or `__init__`. Others are names we recognize from the class definition, such as `print_point`."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Question**. What names do you see in the `point_instance` that we explicitly provided in the `class` definition?"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<font size=8 color=\"#009600\">&#9998;</font> Names:"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Dot access\n",
    "When we make an instance of a class, we can access its attributes using the \"dot\" syntax. For example:\n",
    "\n",
    "`point_instance.x_coord`\n",
    "\n",
    "We have seen this before but to review. We have an instance on the lhs (left hand side) of the \"dot\" and an attribute on the rhs (right hand sice).\n",
    "\n",
    "In this notation we are accessing the rhs attribute that **should** exist in the lhs instance. That attribute could be:\n",
    "- a data attribute, a value stored in the lhs instance\n",
    "- a function attribute, often called a **method**, that can be called in the context of the lhs instance"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Question** Give a list of the data attributes and methods **we**, the user, defined for the point class."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<font size=8 color=\"#009600\">&#9998;</font> Data Attributes:"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<font size=8 color=\"#009600\">&#9998;</font> Function Attributes/Methods:"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Question** Pick a data attribute of `Point`? What type is it? Pick a method attribute of `Point`? What type is it? Write some code that would show those types."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# your code here"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Creating Data Attributes in Instances\n",
    "For *user defined* classes, you can add a new data attribute to an instance by simple assignment using \"dot assignment\" to an instance. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "my_point = Point(x=10, y=10)\n",
    "my_point.new_attribute = 1000\n",
    "print(\"point_instance 'stuff':\",dir(point_instance))\n",
    "print(\"my_point 'stuff':\",dir(my_point))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Question** is `new_attribute` in `point_instance`? Why or why not?"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<font size=8 color=\"#009600\">&#9998;</font> Answer:"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You can see that `new_attribute` is now a part of `my_point`, created when we did the assignment. It is not part of `point_instance` even though they are both of type `Point`. \n",
    "\n",
    "Just like assignment can create a variable, assignment can create an attribute **inside** an instance, any instance that is of a user defined type. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Calling a Method, a Functional Attribute\n",
    "A **method** is a function that is particular to a particular type. Some of its attributes:\n",
    "\n",
    "- A method is called using the \"dot\" call, in the context of a particular instance\n",
    "- A method can only be used on an instance of the correct type.\n",
    "- We define methods in a class so that all instances of the class have access to that method"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Some Examples"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "my_list = [10,20,30]\n",
    "print(type(my_list))    # it is of type list\n",
    "print(my_list.pop())    # call the pop method on the list instance my_list\n",
    "print(dir(my_list))     # these are the methods we can call"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "my_list.upper()         # can't do that, only strings have an upper method"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(dir(my_point))      # what methods are in our class?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "my_point.print_point()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "my_list.print_point()    # a method of type Point, not list"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "my_point.pop()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Question** Some of the expressions above give errors. Why is that?"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<font size=8 color=\"#009600\">&#9998;</font> Answer:"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Assignment wrap-up\n",
    "\n",
    "Please fill out the form that appears when you run the code below.  **You must completely fill this out in order to receive credit for the assignment!**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from IPython.display import HTML\n",
    "HTML(\n",
    "\"\"\"\n",
    "<iframe \n",
    "\tsrc=\"https://cmse.msu.edu/cmse202-pc-survey\" \n",
    "\twidth=\"800px\" \n",
    "\theight=\"600px\" \n",
    "\tframeborder=\"0\" \n",
    "\tmarginheight=\"0\" \n",
    "\tmarginwidth=\"0\">\n",
    "\tLoading...\n",
    "</iframe>\n",
    "\"\"\"\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---------\n",
    "### Congratulations, you're done with your pre-class assignment!\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",
    "\n",
    "\n",
    "&#169; Copyright Michigan State University Board of Trustees"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "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.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
