Class and Object Terms

The foundations of Object-Oriented Programming is defining a Class

  • In Object-Oriented Programming (OOP), a class is a blueprint for creating an Object. (a data structure). An Object is used like many other Python variables.
  • A Class has ...
    • a collection of data, these are called Attributes and in Python are pre-fixed using the keyword self
    • a collection of Functions/Procedures. These are called *Methods when they exist inside a Class definition.
  • An Object is created from the Class/Template. Characteristics of objects ...
    • an Object is an Instance of the Class/Template
    • there can be many Objects created from the same Class
    • each Object contains its own Instance Data
    • the data is setup by the Constructor, this is the "init" method in a Python class
    • all methods in the Class/Template become part of the Object, methods are accessed using dot notation (object.method())
  • A Python Class allow for the definition of @ decorators, these allow access to instance data without the use of functions ...
    • @property decorator (aka getter). This enables developers to reference/get instance data in a shorthand fashion (object.name versus object.get_name())
    • @name.setter decorator (aka setter). This enables developers to update/set instance data in a shorthand fashion (object.name = "John" versus object.set_name("John"))
    • observe all instance data (self._name, self.email ...) are prefixed with "", this convention allows setters and getters to work with more natural variable name (name, email ...)

Hacks

Add new attributes/variables to the Class. Make class specific to your CPT work.

  • Add classOf attribute to define year of graduation =
    • Add setter and getter for classOf =
  • Add dob attribute to define date of birth =
    • This will require investigation into Python datetime objects as shown in example code below =
    • Add setter and getter for dob =
  • Add instance variable for age, make sure if dob changes age changes
    • Add getter for age, but don't add/allow setter for age
  • Update and format tester function to work with changes

Class and Object Code

from werkzeug.security import generate_password_hash, check_password_hash
from datetime import date
import json

class User:    

    def __init__(self, name, uid, password, classOf, dob):
        self._name = name    # variables with self prefix become part of the object, 
        self._uid = uid
        self.set_password(password)
        self._classOf = classOf
        if type(dob) is date:
            self._dob = dob
            self.calculate_age()
        else:
            #terminates the code if type of dob isn't in datetime format. user has to start over. good for debugging
            raise Exception('dob is not in correct type!!')
    
    @property
    def name(self):
        return self._name
    
    # a setter function, allows name to be updated after initial object creation
    @name.setter
    def name(self, name):
        self._name = name
    
    # a classOf getter
    @property
    def classOf(self):
        return self._classOf

    # a setter function to set the users graduating class
    @classOf.setter
    def classOf(self, classOf):
        self._classOf = classOf

    #check if class parameter matchers user class in object
    def is_classOf(self, classOf):
        return self._classOf == classOf

    # a getter method, extracts email from object
    @property
    def uid(self):
        return self._uid
    
    # a setter function, allows name to be updated after initial object creation
    @uid.setter
    def uid(self, uid):
        self._uid = uid
        
    # check if uid parameter matches user id in object, return boolean
    def is_uid(self, uid):
        return self._uid == uid
    
    # dob property is returned as string, to avoid unfriendly outcomes
    @property
    def dob(self):
        dob_string = self._dob.strftime('%m-%d-%Y')
        return dob_string
    
    # dob should be have verification for type date
    @dob.setter
    def dob(self, dob):
        self._dob = dob
        self.calculate_age() #calls calculate_age function whenever user wants to change their dob
        
    # age is returned instead of calculating every single time because its already been assigned to the object in the calculate_age function
    @property
    def age(self):
        return self._age
    
    #calculates age and stores it by assigning it to object
    def calculate_age(self):
        today = date.today()
        #stores calculated age in the object self.
        self._age = today.year - self._dob.year - ((today.month, today.day) < (self._dob.month, self._dob.day))
       
    # dictionary is customized, removing password for security purposes
    @property
    def dictionary(self):
        dict = {
            "name" : self.name,
            "uid" : self.uid,
            "dob" : self.dob,
            "age" : self.age,
            "class" : self.classOf
        }
        return dict
    
    # update password, this is conventional setter
    def set_password(self, password):
        """Create a hashed password."""
        self._password = generate_password_hash(password, method='sha256')

    # check password parameter versus stored/encrypted password
    def is_password(self, password):
        """Check against hashed password."""
        result = check_password_hash(self._password, password)
        return result
    
    # output content using json dumps, this is ready for API response
    def __str__(self):
        return json.dumps(self.dictionary)
    
    # output command to recreate the object, uses attribute directly
    def __repr__(self):
        return f'User(name={self._name}, uid={self._uid}, password={self._password},dob={self._dob}, class={self._classOf})'
    

if __name__ == "__main__":
    u1 = User(name='Thomas Edison', uid='toby', password='123toby', classOf=1999, dob=date(1847, 2, 11))
    print("JSON ready string:\n", u1, "\n") 
    print("Raw Variables of object:\n", vars(u1), "\n") 
    print("Raw Attributes and Methods of object:\n", dir(u1), "\n")
    print("Representation to Re-Create the object:\n", repr(u1), "\n") 
    u2 = User(name='Vivian', uid='vivian', password='123vivian', classOf=1999, dob="1847, 2, 11")
JSON ready string:
 {"name": "Thomas Edison", "uid": "toby", "dob": "02-11-1847", "age": 175, "class": 1999} 

Raw Variables of object:
 {'_name': 'Thomas Edison', '_uid': 'toby', '_password': 'sha256$hWMZkBVAgwExf3Y8$79b6c4b2c9aa3246146b9ca1c15b414eacc9f783da61132bd1f7b0cdc6d65b79', '_classOf': 1999, '_dob': datetime.date(1847, 2, 11), '_age': 175} 

Raw Attributes and Methods of object:
 ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_age', '_classOf', '_dob', '_name', '_password', '_uid', 'age', 'calculate_age', 'classOf', 'dictionary', 'dob', 'is_classOf', 'is_password', 'is_uid', 'name', 'set_password', 'uid'] 

Representation to Re-Create the object:
 User(name=Thomas Edison, uid=toby, password=sha256$hWMZkBVAgwExf3Y8$79b6c4b2c9aa3246146b9ca1c15b414eacc9f783da61132bd1f7b0cdc6d65b79,dob=1847-02-11, class=1999) 

---------------------------------------------------------------------------
Exception                                 Traceback (most recent call last)
c:\Users\vivia\vscode\FastPages\_notebooks\2023-01-10-PBL-model.ipynb Cell 5 in <cell line: 111>()
    <a href='vscode-notebook-cell:/c%3A/Users/vivia/vscode/FastPages/_notebooks/2023-01-10-PBL-model.ipynb#X11sZmlsZQ%3D%3D?line=114'>115</a> print("Raw Attributes and Methods of object:\n", dir(u1), "\n")
    <a href='vscode-notebook-cell:/c%3A/Users/vivia/vscode/FastPages/_notebooks/2023-01-10-PBL-model.ipynb#X11sZmlsZQ%3D%3D?line=115'>116</a> print("Representation to Re-Create the object:\n", repr(u1), "\n") 
--> <a href='vscode-notebook-cell:/c%3A/Users/vivia/vscode/FastPages/_notebooks/2023-01-10-PBL-model.ipynb#X11sZmlsZQ%3D%3D?line=116'>117</a> u2 = User(name='Vivian', uid='vivian', password='123vivian', classOf=1999, dob="1847, 2, 11")

c:\Users\vivia\vscode\FastPages\_notebooks\2023-01-10-PBL-model.ipynb Cell 5 in User.__init__(self, name, uid, password, classOf, dob)
     <a href='vscode-notebook-cell:/c%3A/Users/vivia/vscode/FastPages/_notebooks/2023-01-10-PBL-model.ipynb#X11sZmlsZQ%3D%3D?line=13'>14</a>     self.calculate_age()
     <a href='vscode-notebook-cell:/c%3A/Users/vivia/vscode/FastPages/_notebooks/2023-01-10-PBL-model.ipynb#X11sZmlsZQ%3D%3D?line=14'>15</a> else:
     <a href='vscode-notebook-cell:/c%3A/Users/vivia/vscode/FastPages/_notebooks/2023-01-10-PBL-model.ipynb#X11sZmlsZQ%3D%3D?line=15'>16</a>     #terminates the code. user has to start over
---> <a href='vscode-notebook-cell:/c%3A/Users/vivia/vscode/FastPages/_notebooks/2023-01-10-PBL-model.ipynb#X11sZmlsZQ%3D%3D?line=16'>17</a>     raise Exception('dob is not in correct type!!')

Exception: dob is not in correct type!!

Start a class design for each of your own Full Stack CPT sections of your project

  • Use new code cell in this notebook
  • Define init and self attributes
  • Define setters and getters
  • Make a tester
import json

class Car:    

    def __init__(self, name, color, price):
        self._name = name    # variables with self prefix become part of the object, 
        self._color = color
        self._price = price
        self.determine_value()
    
    # gets the name of the manufacturer or the car
    @property
    def name(self):
        return self._name
    
    # a setter function, allows name to be updated after initial object creation
    @name.setter
    def name(self, name):
        self._name = name
    
    # a color getter
    @property
    def color(self):
        return self._color

    # a setter function to set the car's color
    @color.setter
    def color(self, color):
        self._color = color
    
     # a price getter
    @property
    def price(self):
        return self._price

    # a setter function to set the car's price 
    @price.setter
    def price(self, price):
        self._price = price
        self.determine_value() #calls function whenever price of car changes 
         
    @property
    def value(self):
        return self._value
    
    #determines car value based on price and stores it by assigning it to object
    def determine_value(self):
        if self._price > 60000:
            self._value = "Luxury Car"
        elif self._price in range(30000, 60000):
            self._value ="Middle-end Car"
        else:
            self._value ="Low-end/Second-hand Car"

    # dictionary is customized, removing password for security purposes
    @property
    def dictionary(self):
        dict = {
            "name" : self.name,
            "color" : self.color,
            "price" : self.price,
            "value" : self.value
        }
        return dict
    
    
    # output content using json dumps, this is ready for API response
    def __str__(self):
        return json.dumps(self.dictionary)
    
    # output command to recreate the object, uses attribute directly
    def __repr__(self):
        return f'User(name={self._name}, color={self._color}, price={self._price})'
    

if __name__ == "__main__":
    u1 = Car(name='Toyota', color='white', price=6000)
    print("JSON ready string:\n", u1, "\n") 
    print("Raw Variables of object:\n", vars(u1), "\n") 
    print("Raw Attributes and Methods of object:\n", dir(u1), "\n")
    print("Representation to Re-Create the object:\n", repr(u1), "\n") 
JSON ready string:
 {"name": "Toyota", "color": "white", "price": 6000, "value": "Low-end/Second-hand Car"} 

Raw Variables of object:
 {'_name': 'Toyota', '_color': 'white', '_price': 6000, '_value': 'Low-end/Second-hand Car'} 

Raw Attributes and Methods of object:
 ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_color', '_name', '_price', '_value', 'color', 'determine_value', 'dictionary', 'name', 'price', 'value'] 

Representation to Re-Create the object:
 User(name=Toyota, color=white, price=6000)