{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<h1>11. Introduction to Object-Oriented Programming</h1>\n",
    "<h2>10/27/2023</h2>\n",
    "\n",
    "<h2>11.0 Last Time...</h2>\n",
    "<ul>\n",
    "    <li>NetCDF is a powerful file type containing global attributes, variables, variable attributes, and dimensions.</li>\n",
    "    <li>We can read from NetCDF files using similar syntax to that for regular files.</li>\n",
    "    <li>Using attributes such as 'dimensions' and 'variables', we can learn about individual variables in the dataset.</li>\n",
    "    <li>We can also write to NetCDF files in a simlar way.</li>\n",
    "</ul>\n",
    "\n",
    "<h2>11.1 What is Object-Oriented Programming?</h2>\n",
    "\n",
    "OOP is presented here in opposition to procedural programming. <b>Procedural</b> programs consider two entities: data and functions. Procedurally, the two things are different: a function will take data as input and return data as output (this should sound familiar!). There's nothing customizable about a function with respect to data, which means you can use functions on various types of data with no restrictions... which can you get into trouble.\n",
    "\n",
    "In reality, though, we tend to think of things as having both \"state\" and \"behavior\". People can have a state (tall, short, etc.) but also a behavior (playing basketball, running, etc.), and the two can happen simultaneously.\n",
    "\n",
    "Object-oriented programming attempts to imitate this approach, so specific objects in the code will have a state and a behavior attached to them.\n",
    "\n",
    "<h2>11.2 What is an Object?</h2>\n",
    "\n",
    "An object in programming has two entities attached to it: data... and the things that <i>act</i> on that data. The data are called <b>attributes</b>, and the functions attached to the object that can act on that data are called <b>methods</b>. \n",
    "\n",
    "These methods are specifically made to act on attributes; they aren't just random functions meant as one-size-fits-all solutions, which is what we would see in procedural programming.\n",
    "\n",
    "Objects are generally specific realizations of some <b>class</b> or <b>type</b>. As an example, individual people are specific realizations of the <b>class</b> of human beings. Specific realizations (instances) differ from each other in details but have the same overall pattern. In OOP, specific realizations are <b>instances</b> and common patterns are <b>classes</b>.\n",
    "\n",
    "<h2>11.3 How do Objects Work?</h2>\n",
    "\n",
    "In Python, strings (like almost everything in Python) are objects. Built into Python, there is a class called 'strings', and each time you make a new string, you're using that definition. Python implicitly defines attributes and methods for all string objects; no matter what string you create, you have that set of data and functions associated with your string."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['__add__',\n",
       " '__class__',\n",
       " '__contains__',\n",
       " '__delattr__',\n",
       " '__dir__',\n",
       " '__doc__',\n",
       " '__eq__',\n",
       " '__format__',\n",
       " '__ge__',\n",
       " '__getattribute__',\n",
       " '__getitem__',\n",
       " '__getnewargs__',\n",
       " '__getstate__',\n",
       " '__gt__',\n",
       " '__hash__',\n",
       " '__init__',\n",
       " '__init_subclass__',\n",
       " '__iter__',\n",
       " '__le__',\n",
       " '__len__',\n",
       " '__lt__',\n",
       " '__mod__',\n",
       " '__mul__',\n",
       " '__ne__',\n",
       " '__new__',\n",
       " '__reduce__',\n",
       " '__reduce_ex__',\n",
       " '__repr__',\n",
       " '__rmod__',\n",
       " '__rmul__',\n",
       " '__setattr__',\n",
       " '__sizeof__',\n",
       " '__str__',\n",
       " '__subclasshook__',\n",
       " 'capitalize',\n",
       " 'casefold',\n",
       " 'center',\n",
       " 'count',\n",
       " 'encode',\n",
       " 'endswith',\n",
       " 'expandtabs',\n",
       " 'find',\n",
       " 'format',\n",
       " 'format_map',\n",
       " 'index',\n",
       " 'isalnum',\n",
       " 'isalpha',\n",
       " 'isascii',\n",
       " 'isdecimal',\n",
       " 'isdigit',\n",
       " 'isidentifier',\n",
       " 'islower',\n",
       " 'isnumeric',\n",
       " 'isprintable',\n",
       " 'isspace',\n",
       " 'istitle',\n",
       " 'isupper',\n",
       " 'join',\n",
       " 'ljust',\n",
       " 'lower',\n",
       " 'lstrip',\n",
       " 'maketrans',\n",
       " 'partition',\n",
       " 'removeprefix',\n",
       " 'removesuffix',\n",
       " 'replace',\n",
       " 'rfind',\n",
       " 'rindex',\n",
       " 'rjust',\n",
       " 'rpartition',\n",
       " 'rsplit',\n",
       " 'rstrip',\n",
       " 'split',\n",
       " 'splitlines',\n",
       " 'startswith',\n",
       " 'strip',\n",
       " 'swapcase',\n",
       " 'title',\n",
       " 'translate',\n",
       " 'upper',\n",
       " 'zfill']"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# The dir() command gives you a list of all the attributes and methods\n",
    "# associated with a given object.\n",
    "a = \"hello world\"\n",
    "dir(a)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Hello World\n",
      "HELLO WORLD\n"
     ]
    }
   ],
   "source": [
    "# To refer to an attribute or method of an instance,\n",
    "# you just add a period after the object name and then put\n",
    "# the attribute or method name.\n",
    "print(a.title())\n",
    "print(a.upper())\n",
    "# Methods can produce a return value, act on attributes of the object in-place,\n",
    "# or both!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "True\n"
     ]
    }
   ],
   "source": [
    "# isupper() will determine whether the object is in uppercase.\n",
    "b = \"BALLS\"\n",
    "print(b.isupper())\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "3\n"
     ]
    }
   ],
   "source": [
    "# To count the instances of a particular character, you can use count()\n",
    "print(a.count(\"l\"))\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "As another example, let's consider how objects work for arrays!\n",
    "\n",
    "Arrays have attributes and methods built in to them just like any other object."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[ 0.  1.  2.]\n",
      " [ 3.  4.  5.]\n",
      " [ 6.  7.  8.]\n",
      " [ 9. 10. 11.]]\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "a = np.arange(12.)\n",
    "a = np.reshape(a,(4,3))\n",
    "print(a)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['T', '__abs__', '__add__', '__and__', '__array__', '__array_finalize__', '__array_function__', '__array_interface__', '__array_prepare__', '__array_priority__', '__array_struct__', '__array_ufunc__', '__array_wrap__', '__bool__', '__class__', '__class_getitem__', '__complex__', '__contains__', '__copy__', '__deepcopy__', '__delattr__', '__delitem__', '__dir__', '__divmod__', '__dlpack__', '__dlpack_device__', '__doc__', '__eq__', '__float__', '__floordiv__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getstate__', '__gt__', '__hash__', '__iadd__', '__iand__', '__ifloordiv__', '__ilshift__', '__imatmul__', '__imod__', '__imul__', '__index__', '__init__', '__init_subclass__', '__int__', '__invert__', '__ior__', '__ipow__', '__irshift__', '__isub__', '__iter__', '__itruediv__', '__ixor__', '__le__', '__len__', '__lshift__', '__lt__', '__matmul__', '__mod__', '__mul__', '__ne__', '__neg__', '__new__', '__or__', '__pos__', '__pow__', '__radd__', '__rand__', '__rdivmod__', '__reduce__', '__reduce_ex__', '__repr__', '__rfloordiv__', '__rlshift__', '__rmatmul__', '__rmod__', '__rmul__', '__ror__', '__rpow__', '__rrshift__', '__rshift__', '__rsub__', '__rtruediv__', '__rxor__', '__setattr__', '__setitem__', '__setstate__', '__sizeof__', '__str__', '__sub__', '__subclasshook__', '__truediv__', '__xor__', 'all', 'any', 'argmax', 'argmin', 'argpartition', 'argsort', 'astype', 'base', 'byteswap', 'choose', 'clip', 'compress', 'conj', 'conjugate', 'copy', 'ctypes', 'cumprod', 'cumsum', 'data', 'diagonal', 'dot', 'dtype', 'dump', 'dumps', 'fill', 'flags', 'flat', 'flatten', 'getfield', 'imag', 'item', 'itemset', 'itemsize', 'max', 'mean', 'min', 'nbytes', 'ndim', 'newbyteorder', 'nonzero', 'partition', 'prod', 'ptp', 'put', 'ravel', 'real', 'repeat', 'reshape', 'resize', 'round', 'searchsorted', 'setfield', 'setflags', 'shape', 'size', 'sort', 'squeeze', 'std', 'strides', 'sum', 'swapaxes', 'take', 'tobytes', 'tofile', 'tolist', 'tostring', 'trace', 'transpose', 'var', 'view']\n"
     ]
    }
   ],
   "source": [
    "# Now let's look at all the attributes and methods!\n",
    "print(dir(a))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(4, 3)\n"
     ]
    }
   ],
   "source": [
    "# Any attributes with two underscores probably shouldn't\n",
    "# be messed with! This is how Python decides what to do when\n",
    "# you type '*' or '/'.\n",
    "\n",
    "# Some of the other interesting methods include:\n",
    "\n",
    "print(np.shape(a))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 0.,  1.,  3.,  6., 10., 15., 21., 28., 36., 45., 55., 66.])"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a.cumsum()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[ 0.  3.  6.  9.]\n",
      " [ 1.  4.  7. 10.]\n",
      " [ 2.  5.  8. 11.]]\n"
     ]
    }
   ],
   "source": [
    "print(a.T)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 0.,  0.,  0.],\n",
       "       [ 0.,  0.,  0.],\n",
       "       [10., 10., 10.],\n",
       "       [10., 10., 10.]])"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a.round(-1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 0.,  1.,  2.,  3.,  4.,  5.,  6.,  7.,  8.,  9., 10., 11.])"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a.ravel()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<b>Practice Exercises!</b>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "The rain in Spain.\n",
      "THE RAIN IN SPAIN.\n",
      "True\n",
      "3\n"
     ]
    }
   ],
   "source": [
    "a = 'The rain in Spain.'\n",
    "#1. Create a new string b that is a but all in uppercase.\n",
    "b = a.upper()\n",
    "#2. Is a changed when you create b?\n",
    "print(a)\n",
    "print(b)\n",
    "# no?\n",
    "#3. How would you test to see whether b is in uppercase? That is, how \n",
    "#   could you return a boolean that is True or False depending on whether \n",
    "#   b is uppercase?\n",
    "print(b.isupper())\n",
    "#4. How would you calculate the number of occurrences of the letter 'n' in a?\n",
    "print(a.count(\"n\"))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<b>Round 2!</b>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[2.3 8.  3.2]\n",
      " [4.3 0.4 4.3]\n",
      " [1.2 0.3 5.4]\n",
      " [4.3 5.6 6.5]]\n",
      "[2.3 8.  3.2 4.3 0.4 4.3 1.2 0.3 5.4 4.3 5.6 6.5]\n",
      "[[2.3 8.  3.2 4.3 0.4 4.3]\n",
      " [1.2 0.3 5.4 4.3 5.6 6.5]]\n"
     ]
    }
   ],
   "source": [
    "#1. Create a 3 column, 4 row array named a. The array can have any numerical values\n",
    "#   you want, as long as all the elements are not all identical.\n",
    "x = np.array([[2.3,4.3,1.2,4.3],[8.0,0.4,0.3,5.6],[3.2,4.3,5.4,6.5]])\n",
    "x = x.T\n",
    "print(x)\n",
    "#2. Create an array b that is a copy of a but is 1-D, not 2-D.\n",
    "b = np.ravel(x)\n",
    "print(b)\n",
    "#3. Turn b into a 6 column, 2 row array.\n",
    "b = np.reshape(b,(2,6))\n",
    "#4. Create an array c where you round all elements of b to 1 decimal place.\n",
    "c = b.round(1)\n",
    "print(c)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<h2>11.4 Take-Home Points</h2>\n",
    "<ul>\n",
    "    <li><b>Objects</b> have attributes and methods associated with them that can be listed using <b>dir()</b>.</li>\n",
    "    <li>Methods for strings include <b>upper()</b>, <b>isupper()</b>, <b>count()</b>, <b>title()</b>, etc.</li>\n",
    "    <li>Methods for arrays include <b>reshape()</b>, <b>ravel()</b>, <b>round()</b>, etc.</li>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "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.11.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
