Basic Object Orientated Methods#

Follow these simple OOP exercises to practice and gain confidence in coding classes.

Exercise 1#

Task:

  • Create a class called Patient.

  • The class should contain a constructor that accepts the following parameters. The parameters should be stored in appropriately named attributes.

    • patient_id: int

    • age: int

Hints

  • Don’t forget to include the self parameter!

  • Make sure you use correct case for the class name. Patient follows PEP8 guidelines while patient does not!

# your code here ...
# example solution
class Patient:
    def __init__(self, patient_id, age):
        self.id = patient_id
        self.age = age

Exercise 2:#

Task:

  • Create a class called Ward

  • Code a constructor method.

    • It should accept ward_id (int) as parameter and assign it to an attribute

    • It should create a new empty list attribute that will hold patients staying on the ward.

  • Create a method called add_patient. It should accept a parameter called patient (that is a patient class).

  • Create a method or property called n_patients. It should return the number of patients on the ward.

Hints:

  • Don’t forget the self parameter in the method!

class Ward:
    def __init__(self, ward_id):
        self.ward_id = ward_id 
        self.patients = []
        
    def add_patient(self, patient): 
        self.patients.append(patient)
    
    @property
    def n_patients(self):
        '''
        Number of the patients...
        '''
        return len(self.patients)

Exercise 3:#

You will now test the Ward class by generating a number of patients and adding them to a ward object.

Task:

  • Code a function that first creates a Ward object and then adds a user specified number of Patient instances via the add_patient function.

  • The function must return the ward object.

  • Test your function with 5 patients.

Hints:

  • You will need to design the function so that it allocates a patient an age. One option is to randomly generate an age in a given range. You could achieve this using the random.randint() function. E.g.

from random import randint
lower, upper = 60, 95
age = randint(lower, upper)

# your code here ...
# example solution
from random import randint

def new_ward(ward_id, n_patients, age_range=(60,95)):
    '''
    Create a new ward with an id.
    The ward will contain n_patients with random
    age
    
    Params:
    ------
    ward_id: int 
        Unique id of ward
        
    n_patients: int
        Number of patients on ward
        
    age_range: (int, int), optional (default=(60,95))
        Age range for random allocation to patients.
        
    Returns:
    -------
    Ward
    
    '''
    ward = Ward(ward_id)
    
    for i in range(n_patients):
        to_add = Patient(i, randint(age_range[0], age_range[1]))
        ward.add_patient(to_add)
    return ward
WARD_ID = 1
N_PATIENTS = 5

ward = new_ward(WARD_ID, N_PATIENTS)

# test
print(len(ward.patients))
print(ward.patients[4].id)
print(ward.patients[4].age)
5
4
87

Exercise 4:#

Task:

  • Now create a Hospital class

  • The class should allow the creation of new wards as well as adding a patient to a user specified ward.

  • The class must provide a n_patients method or property that returns the uptodate total of patients in the hospital.

  • Create some test data and create a Hospital object. Return the total number of patients in the hospital.

# your code here ...
class Hospital:
    '''
    Encapsulates a hosptial made up of wards...
    '''
    def __init__(self, n_patients, age_ranges):
        self.wards = [new_ward(i, n_patients[i], age_ranges[i]) 
                               for i in range(len(n_patients))]
    
    def add_patient(self, ward_id, patient):
        self.wards[ward_id].add_patient(patient)
        
    def add_ward(self, n_patients=0, age_range=(60, 95)):
        to_add = new_ward(len(self.wards), n_patients, age_range)
        self.wards.append(to_add)
    
    @property
    def n_patients(self):
        return sum([ward.n_patients for ward in self.wards])
    
    @property
    def n_wards(self):
        return len(self.wards)
# age ranges
DEFAULT_RANGE = (60, 95)
YOUNG_ADULTS = (18,25)
DAY_CASES = (18, 88)

# parameters
n_patients= [5, 10, 8, 6, 15]
age_ranges = [DEFAULT_RANGE, DEFAULT_RANGE, DEFAULT_RANGE, YOUNG_ADULTS, 
              DAY_CASES]


# init hospital
hosp = Hospital(n_patients, age_ranges)

# test
hosp.n_patients
44

Exercise 5#

Task:

Let’s create a new type of patient specific to those with respiratory conditions.

The new class will also accept patient_id and age. You will need to create two new parameters as well: pack_yrs and fev1. Fyi:

  • A pack year is defined as twenty cigarettes smoked everyday for one year

  • FEV1 stands for Forced Expiratory Volumne and is a percentage measured out of 100%. Lower values are worse.

Call the class RespiratoryPatient

# example solution via inheritance
class RespiratoryPatient(Patient):
    def __init__(self, patient_id, age, pack_yrs, fev1):
        super().__init__(patient_id, age)
        self.pack_yrs = pack_yrs
        self.fev1 = fev1
# test
resp_patient = RespiratoryPatient(1, 25, 10, 80.0)
print(resp_patient.id)
print(resp_patient.age)
print(resp_patient.fev1)
1
25
80.0
# example solution via object composition

class RespiratoryPatient:
    def __init__(self, patient, pack_yrs, fev1):
        self.patient = patient
        self.pack_yrs = pack_yrs
        self.fev1 = fev1
    
    @property
    def id(self):
        return self.patient.id
    
    @property
    def age(self):
        return self.patient.age
# test composition...
patient = Patient(1, 25)
resp_patient = RespiratoryPatient(patient, 10, 80.0)
print(resp_patient.id)
print(resp_patient.age)
print(resp_patient.fev1)
1
25
80.0