{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### <center>San Jose State University<br>Department of Applied Data Science<br><br>**DATA 200<br>Computational Programming for Data Analytics**<br><br>Spring 2024<br>Instructor: Ron Mak</center>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 10.4.2 Class `Time` Definition\n",
    "#### We define class `Time` is in module `timewithproperties` (Python source file `timewithproperties.py`)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from timewithproperties import Time"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Class Time: `__init__` Method with Default Parameter Values\n",
    "```python\n",
    "class Time:\n",
    "    \"\"\"\n",
    "    Class Time with read-write properties.\n",
    "    \"\"\"\n",
    "\n",
    "    def __init__(self, hour=0, minute=0, second=0):\n",
    "        \"\"\"\n",
    "        Constructor of a Time object with default values.\n",
    "        \"\"\"\n",
    "        self._hour   = hour    # 0-23\n",
    "        self._minute = minute  # 0-59\n",
    "        self._second = second  # 0-59\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Class `Time`: `hour` Read-Write Property\n",
    "#### We designate `hour` to be a publicly accessible **read-write property** and implement it as a **getter** method that access the value of the private attribute `_hour`. In this example, we return the hour in the 12-hour format.\n",
    "```python\n",
    "    @property\n",
    "    def hour(self):\n",
    "        \"\"\"\n",
    "        @return the hour in the 12-hour format.\n",
    "        \"\"\"\n",
    "        return self._hour if self._hour <= 12 else self._hour - 12"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### We can also define a **setter** method for the property which **validates** its parameter value.\n",
    "```python\n",
    "    @hour.setter\n",
    "    def hour(self, hour):\n",
    "        \"\"\"\n",
    "        Set the hour.\n",
    "        @param hour the hour to set.\n",
    "        \"\"\"\n",
    "        if not (0 <= hour < 24):\n",
    "            raise ValueError(f'Hour ({hour}) must be 0-23')\n",
    "\n",
    "        self._hour = hour\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### At run time, `wake_up.hour` implicitly calls the property's getter method and `wake_up.hour = 100` implicitly calls its setter method."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "wake_up = Time(hour=6, minute=30)\n",
    "wake_up.hour"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "bedtime = Time(hour=22)\n",
    "bedtime"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "bedtime.hour"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "wake_up.hour = 100"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Class `Time`: `minute` and `second` Read-Write Properties\n",
    "```python\n",
    "    @property\n",
    "    def minute(self):\n",
    "        \"\"\"\n",
    "        @return the minute.\n",
    "        \"\"\"\n",
    "        return self._minute\n",
    "\n",
    "    @minute.setter\n",
    "    def minute(self, minute):\n",
    "        \"\"\"\n",
    "        Set the minute.\n",
    "        @param minute the minute to set.\n",
    "        \"\"\"\n",
    "        if not (0 <= minute < 60):\n",
    "            raise ValueError(f'Minute ({minute}) must be 0-59')\n",
    "\n",
    "        self._minute = minute\n",
    "\n",
    "    @property\n",
    "    def second(self):\n",
    "        \"\"\"\n",
    "        @return the second.\n",
    "        \"\"\"\n",
    "        return self._second\n",
    "\n",
    "    @second.setter\n",
    "    def second(self, second):\n",
    "        \"\"\"\n",
    "        Set the second.\n",
    "        @param second the second to set.\n",
    "        \"\"\"\n",
    "        if not (0 <= second < 60):\n",
    "            raise ValueError(f'Second ({second}) must be 0-59')\n",
    "\n",
    "        self._second = second\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Class `Time`: Method `set_time` \n",
    "```python\n",
    "    def set_time(self, hour=0, minute=0, second=0):\n",
    "        \"\"\"\n",
    "        Set the hour, minute, and second by invoking the setters.\n",
    "        @param hour the hour to set.\n",
    "        @param minute the minute to set.\n",
    "        @param second the second to set.\n",
    "        \"\"\"\n",
    "        self.hour   = hour\n",
    "        self.minute = minute\n",
    "        self.second = second\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Class `Time`: Special Method `__repr__()`\n",
    "#### Every class has a method `__repr__()` the is implicitly called to return an object's \"official\" string representation. You can **override** its default code.\n",
    "```python\n",
    "    def __repr__(self):\n",
    "        \"\"\"\n",
    "        @return the string representation of the Time object.\n",
    "        \"\"\"\n",
    "        return (f'Time(hour={self._hour}, minute={self._minute}, ' + \n",
    "                f'second={self._second})')\n",
    "```\n",
    "#### The string representation is supposed to look like a constuctor call. The method is also implicitly called when you display an object."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "wake_up"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "display(wake_up)"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Class `Time`: Special Method `__str__()`\n",
    "#### Every class has a method `__str__()` that is implicitly called to return a formmatted string for calls to str() or print().\n",
    "\n",
    "```python\n",
    "    def __str__(self):\n",
    "        \"\"\"\n",
    "        @return a Time string in 12-hour clock format \n",
    "                for calls to str() or to print().\n",
    "        \"\"\"\n",
    "        return (('12' if self.hour in (0, 12) else str(self.hour%12)) + \n",
    "                f':{self.minute:0>2}:{self.second:0>2}' + \n",
    "                (' AM' if self.hour < 12 else ' PM'))\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(wake_up)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Built-in function`eval()`\n",
    "#### We can call the built-in `eval()` function to parse a string similar to one returned by `__repr__()` and return an object."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "bedtime"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "bedtime_string = 'Time(hour=23, minute=30, second=10)'\n",
    "bedtime = eval(bedtime_string)\n",
    "\n",
    "bedtime"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "##########################################################################\n",
    "# (C) Copyright 2019 by Deitel & Associates, Inc. and                    #\n",
    "# Pearson Education, Inc. All Rights Reserved.                           #\n",
    "#                                                                        #\n",
    "# DISCLAIMER: The authors and publisher of this book have used their     #\n",
    "# best efforts in preparing the book. These efforts include the          #\n",
    "# development, research, and testing of the theories and programs        #\n",
    "# to determine their effectiveness. The authors and publisher make       #\n",
    "# no warranty of any kind, expressed or implied, with regard to these    #\n",
    "# programs or to the documentation contained in these books. The authors #\n",
    "# and publisher shall not be liable in any event for incidental or       #\n",
    "# consequential damages in connection with, or arising out of, the       #\n",
    "# furnishing, performance, or use of these programs.                     #\n",
    "##########################################################################\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Additional material (C) Copyright 2024 by Ronald Mak"
   ]
  }
 ],
 "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.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
