Object Oriented Programming
The post for Object Oriented Programming.
Terms
- Class
- 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.
- Object is a instance of a 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
- 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)
- enables developers to reference/get instance data in a shorthand fashion (object.name versus object.get_name())
- @name.setter decorator (aka setter)
- 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 ""
- allows setters and getters to work with more natural variable name (name, email ...)
- @property decorator (aka getter)
# A gateway in necessary as a web server cannot communicate directly with Python.
# In this case, imports are focused on generating hash code to protect passwords.
from werkzeug.security import generate_password_hash, check_password_hash
import json
from datetime import date
# Define a User Class/Template
# -- A User represents the data we want to manage
class User:
# constructor of a User object, initializes the instance variables within object (self)
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
self.dob=dob
self.age=self.calculate_age()
# a name getter method, extracts name from object
@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 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
@property
def password(self):
return self._password[0:10] + "..." # because of security only show 1st characters
# 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
# getter method for classOf
def get_classOf(self):
return self.classOf
# setter method for classOf
def set_classOf(self,classOf):
self.classOf = classOf
#getter method for DoB
def get_dob(self):
return self.dob
# setter method for DoB and changing age
def set_dob(self,dob):
self.dob = dob
self.age=self.calculate_age()
def calculate_age(self):
today = date.today()
return today.year - self.dob.year - ((today.month, today.day) < (self.dob.month, self.dob.day))
# getter method for age
def get_age(self):
return self.age
# output content using str(object) in human readable form, uses getter
def __str__(self):
return f'name: "{self.name}", id: "{self.uid}", psw: "{self.password}", classOf: "{self.classOf}", dob: "{self.dob}", age: "{self.age}"'
# output command to recreate the object, uses attribute directly
def __repr__(self):
return f'Person(name={self._name}, uid={self._uid}, password={self._password})'
def __dir__(self):
return ["name", "uid"]
# tester method to print users
def tester(users, uid, psw):
result = None
for user in users:
# test for match in database
if user.uid == uid and user.is_password(psw): # check for match
print("* ", end="")
result = user
# print using __str__ method
print(str(user))
return result
# place tester code inside of special if! This allows include without tester running
if __name__ == "__main__":
u = User(name='Alexander Graham Bell', uid='lex', password='123lex', classOf=1858, dob=date(1847,3,3))
# Find user
print("print our user")
print(u)
# Change user
print("changing our user")
u.name = "John Mortensen"
u.uid = "jm1021"
u.set_password("123qwerty")
u.set_classOf(1991)
u.set_dob(date(1959,4,5)) # I have no idea lmao
print(u)
from math import *
class Fraction:
"""represents fractions"""
def __init__(self, num, denom):
"""Fraction(num,denom) -> Fraction
creates the fraction object representing num/denom"""
if denom == 0: # raise an error if the denominator is zero
raise ZeroDivisionError
if num == 0: # set the fraction to 0/1 if numerator is 0
self.num = 0
self.denom = 1
return
positive = True # keeps track of positivity
if denom < 0: # if denominator is negative, change it to positive and keeps track
positive = not positive
denom = -1 * denom
if num < 0: # do the same to numerator
positive = not positive
num = -1 * num
self.num = int(num / gcd(num, denom)) # the gcd only works when both is positive
self.denom = int(denom / gcd(num, denom))
if not positive: # change numerator to negative if positive is false
self.num = -1 * self.num
def set_numerator(self, num):
"""Fraction.set_numerator(num) -> None
changes the numerator of the fraction"""
self.__init__(num, self.denom)
def get_numerator(self):
"""Fraction.get_numerator() -> int
returns the numerator of the fraction"""
return self.num
def set_denominator(self, denom):
"""Fraction.denominator(denom) -> None
changes the denominator of the fraction"""
self.__init__(self.num, denom)
def get_denominator(self):
"""Fraction.get_denominator() -> int
returns the denominators of the fraction"""
return self.denom
def __str__(self):
"""Fraction.__str__() -> string
returns a string representing the fraction"""
return f"{self.num}/{self.denom}"
def __float__(self):
"""Fraction.__float__() -> float
returns a float representing the value of the fraction"""
return self.num / self.denom
def __add__(self, other):
"""Fraction+Fraction -> Fraction
returns a Fraction that is the results of adding two together"""
denomFinal = int(lcm(self.denom, other.denom))
numFinal = int(self.num * denomFinal / self.denom + other.num * denomFinal / other.denom)
return Fraction(numFinal, denomFinal)
def __sub__(self, other):
"""Fraction-Fraction -> Fraction
returns a Fraction that is the results of subtraction one fraction from another"""
denomFinal = int(lcm(self.denom, other.denom))
numFinal = int(self.num * denomFinal / self.denom - other.num * denomFinal / other.denom)
return Fraction(numFinal, denomFinal)
def __mul__(self, other):
"""Fraction*Fraction -> Fraction
returns a Fraction that is the results of multiplying two together"""
return Fraction(self.num * other.num, self.denom * other.denom)
def __truediv__(self, other):
"""Fraction/Fraction -> Fraction
returns a Fraction that is the results of dividing one fraction by another"""
return Fraction(self.num * other.denom, self.denom * other.num)
def __eq__(self, other):
"""Fraction==Fraction -> boolean
returns a boolean saying if two fraction is equal to each other"""
if self.num == other.num and self.denom == other.denom:
return True
else:
return False
a=Fraction(1,2)
b=Fraction(2,3)
print(a,b)
print(a+b)
print(b-a)
print(a*b)
print(b/a)
print(float(a))
print(a.get_numerator())
print(b.get_denominator())
a.set_denominator(4)
b.set_numerator(1)
print(a,b)
print(a==b)