Programming basics for Biostatistics 6099

Objective Oriented Programming

Zhiguang Huo (Caleb)

Tuesday Oct 24th, 2023

Introduction

Introduction

A toy example

class Person:

    def setName(self, aname):
        self.name = aname
    
    def greet(self):
        print("Hi there, my name is " + self.name)

a = Person()
a.setName("Lucas")
a.greet()
## Hi there, my name is Lucas

OOP vocabulary

multiple objects from the same class

a = Person()
a.setName("Lucas")
a.greet()
## Hi there, my name is Lucas
b = Person()
b.setName("Amy")
b.greet()
## Hi there, my name is Amy
c = Person()
c.setName("Beth")
c.greet()
## Hi there, my name is Beth

Class methods

In class exercise (1)

Create a new participant Amy, who is female and 49 years old.
When we use the display_info(), we expect to see

"Participant Amy, 49 yrs, female".
    
class Participant:
    
    def setName(self,name):
        self.name = name
      
    def setAge(self,age):
        self.age = age

    def setGender(self,sex):
        self.sex = sex

    def display_info(self):
        print(f"Participant {self.name}, {self.age} yrs, {self.sex}")

aParticipant = Participant()
aParticipant.setName("Amy")
aParticipant.setAge(49)
aParticipant.setGender("Sex")

aParticipant.display_info()
## Participant Amy, 49 yrs, Sex

Attributes initialization

class Person:
    
    def __init__(self):
        self.name = "John"
    
    def setName(self, aname):
        self.name = aname
    
    def greet(self):
        print("Hi there, my name is " + self.name)

a = Person()
a.setName("Lucas")
a.greet()
## Hi there, my name is Lucas
b = Person()
b.greet()
## Hi there, my name is John

Attributes initialization with a user’s input

class Person:
    
    def __init__(self, aname):
        self.name = aname
    
    def setName(self, aname):
        self.name = aname
    
    def greet(self):
        print("Hi there, my name is " + self.name)

a = Person("Lucas")
b = Person("Amy")

a.greet()
## Hi there, my name is Lucas
b.greet()
## Hi there, my name is Amy

Default value in the initialization

class Person:
    
    def __init__(self, aname="John"):
        self.name = aname
    
    def setName(self, aname):
        self.name = aname
    
    def greet(self):
        print("Hi there, my name is " + self.name)
    
a = Person("Lucas")
a.greet()
## Hi there, my name is Lucas
b = Person()
b.greet()
## Hi there, my name is John

Class methods

In class exercise (2)

Create a new participant Amy, who is female and 49 years old.
When we use the display_info(), we expect to see

"Participant Amy, 49 yrs, female".
    
class Participant:
    def __init__(self, name, age, sex):
        self.name = name
        self.age = age
        self.sex = sex
    
    def setName(self,name):
        self.name = name
      
    def setAge(self,age):
        self.age = age

    def setGender(self,sex):
        self.sex = sex
        
    def display_info(self):
        print(f"Participant {self.name}, {self.age} yrs, {self.sex}")

aParticipant = Participant(name="Amy", age=49, sex="female")
aParticipant.display_info()
## Participant Amy, 49 yrs, female

private method

class Secretive:
    def __inaccessible(self):
        print("Bet you can't see me...")
    def accessible(self):
        print("The secret message is:")
        self.__inaccessible()


s = Secretive()
#s.__inaccessible() ## does not work
s.accessible()
## The secret message is:
## Bet you can't see me...

Class attributes

class Person:
    
    def __init__(self, aname):
        self.name = aname
    
    def getName(self):
        return(self.name)
    
a = Person("Lucas")
a.getName()
## 'Lucas'
a.name  ## alternative way to get attribute
## 'Lucas'

private attribute

class Person:
    
    def __init__(self, aname):
        self.__name = aname
    
    def getName(self):
        return(self.__name)
    
a = Person("Lucas")
a.getName()
#a.__name ## does not work
## 'Lucas'

In class exercise (3)

Create a new participant Amy, who is female and 49 years old.
Also create her phone_number (123-456-7890) by using setPhoneNumber() method.
The phone_number is not directly accessible via class.phone_number.
It is accessible via class.show_contact_number()
class Participant:
    def __init__(self, name, age, sex):
        self.name = name
        self.age = age
        self.sex = sex
    
    def setPhoneNumber(self,anumber):
        self.__phone_number = anumber

    def display_info(self):
        print(f"Participant {self.name}, {self.age} yrs, {self.sex}")

    def show_contact_number(self):
        print(self.__phone_number)
      
aParticipant = Participant(name="Amy", age=49, sex="female")
aParticipant.setPhoneNumber("123-456-7890")
aParticipant.show_contact_number()
## 123-456-7890

extra argument and keywords in the class initialization

class Car:

    def __init__(self, **kw):
        self.make = kw["make"]
        # self.model = kw["model"]
        self.model = kw.get("model")

my_car = Car(make = "Chevo", model = "Malibu")
print(my_car.model)
## Malibu
my_car = Car(make = "Chevo")
print(my_car.model)
## None

a Class with attributes being other class’s objects

class Person:
    
    def __init__(self, aname="John"):
        self.name = aname
    
    def setName(self, aname):
        self.name = aname
    
    def getName(self):
        return(self.name)
    
    def greet(self):
        print("Hi there, my name is " + self.name)

a Group class

class Group:
    
    def __init__(self):
        self.persons = []
    
    def add(self, aperson):
        self.persons.append(aperson)
    
    def getNameAll(self):
        res = [aperson.getName() for aperson in self.persons]
        return(res)
        
agroup = Group()

agroup.add(Person("Amy"))
agroup.add(Person("Beth"))
agroup.add(Person("Carl"))

agroup.getNameAll()
## ['Amy', 'Beth', 'Carl']

In class exercise (4)

Create a study with 5 participants, Amy, Beth, Carl, Dan, Emily.
Sex are randomly choose from male and female.
Age are randomly selected from 20-60.

And then show the mean age and percentage of females.
Also show the info for all participants
class Participant:
    
    def __init__(self, name, age, sex):
        self.name = name
        self.age = age
        self.sex = sex
        
        
    def display_info(self):
        print(f"Participant {self.name}, {self.age} yrs, {self.sex}")
class Study:
    
    def __init__(self):
        self.participants = []
        
    def enroll(self, aparticipant):
        self.participants.append(aparticipant)
        
    def get_mean_age(self):
        pass
      
    def get_percent_female(self):
        pass
    
    def display_all(self):
        for aparticipant in self.participants:
            aparticipant.display_info()
    
astudy = Study()
names = ["Amy", "Beth", "Carl", "Dan", "Emily"]
genders = ["male", "female"]
import random
for aname in names:
  aage = random.randint(20,80)
  asex = random.choice(genders)
  aparticipant = Participant(aname, aage, asex)
  astudy.enroll(aparticipant)

astudy.get_mean_age()
astudy.get_percent_female()
astudy.display_all()
## Participant Amy, 55 yrs, female
## Participant Beth, 56 yrs, male
## Participant Carl, 56 yrs, female
## Participant Dan, 65 yrs, male
## Participant Emily, 74 yrs, male

Class inheritance

class Child(Parent):
class Person:
    
    def __init__(self):
        self.name = "John"
    
    def setName(self, aname):
        self.name = aname
    
    def greet(self):
        print("Hi there, my name is " + self.name)
class Student(Person):
    pass
astudent = Student()
astudent.greet()
## Hi there, my name is John

Class inheritance

The child class can have additional attributes and methods compared to the parent class

class Person:
    
    def __init__(self):
        self.name = "John"
    
    def setName(self, aname):
        self.name = aname
    
    def greet(self):
        print("Hi there, my name is " + self.name)
class Student(Person):
    
    def __init__(self):
        self.courses = {}
    
    def add_course(self, course, grade):
        self.courses.update({course:grade})
        
    def get_ave_grade(self):
        ave_grades = sum(list(self.courses.values()))/len(self.courses)
        return(ave_grades)
astudent = Student()
astudent.setName("Levi")
astudent.greet()
## Hi there, my name is Levi
astudent.add_course("math", 4.0)
astudent.add_course("physics", 3.8)
astudent.add_course("history", 3.7)
astudent.get_ave_grade()
## 3.8333333333333335
issubclass(Person, Student)
## False
issubclass(Student, Person)
## True

Super method for python class

class Animal():
  def __init__(self, animal_type):
    print('Animal Type:', animal_type)
    
class Dog(Animal):
  def __init__(self):

    # call superclass
    super().__init__('dog')
    ## super(Dog, self).__init__('dog') ## alternatively
    print('Wolffff')
    
adog = Dog()
## Animal Type: dog
## Wolffff

In class exercise (5)

class Participant:
    def __init__(self, name, age, sex):
        self.name = name
        self.age = age
        self.sex = sex
    
    def display_info(self):
        print(f"Participant {self.name}, {self.age} yrs, {self.sex}")

aParticipant = Participant(name="Amy", age=49, sex="female")
aParticipant.display_info()
## Participant Amy, 49 yrs, female
def train(self):
    strength += 1
    print(my strength is {strength})

Athlete Class

class Athlete(Participant):
    
    def __init__(self, name, age, sex):
        super(Athlete, self).__init__(name, age, sex) ## need this to initialize the parental class
        ## alternatively, super().__init__(name, age, sex)
        self.strength = 100
    
    def train(self):
        self.strength += 1
        print(f"my strength is {self.strength}")
aAthlete = Athlete(name="Amy", age=49, sex="female")
aAthlete.display_info()
## Participant Amy, 49 yrs, female
aAthlete.strength
## 100
aAthlete.train()
## my strength is 101
aAthlete.strength
## 101

Multiple inheritance

class Calculator:
    def calculate(self, expression):
        self.value = eval(expression) ## eval is to evaluate some expression in python

class Talker:
    def talk(self):
        print("Hi, my value is", self.value)

class TalkingCalculator(Calculator, Talker):
    pass
a = TalkingCalculator()
a.calculate("1+1")
a.talk()
## Hi, my value is 2

Exercise (will be part of HW4)

Exercise (will be part of HW4)

Exercise (will be part of HW4)

Exercise (will be part of HW4)

Reference