Lesson 4

Overview

  1. Classes
  • A class for names
    • Comparing classes and dictionaries
  • A class for students
    • Defining new class attributes
  • A class for classrooms
  1. Queues
  • Standard queues
  • Priority queues
  1. PA3 Review

1. Classes

An easy way to store and handle “related” data/variables

  • Variables stored within a class are accessed using . and are called ‘attributes’
  • Functions within a class are called ‘methods’ and must use self as the first argument
  • The first method for a new class must be __init__

We will build up an example of names -> students -> classrooms

1.1 A class for names

class Name():
    def __init__(self, first_name, last_name, middle_name=None):
        self.first_name = first_name
        self.last_name = last_name
        self.middle_name = middle_name

    def print_name(self):
        if self.middle_name is None:
            print(self.first_name, self.last_name)
        else:
            print(self.first_name, self.middle_name, self.last_name)

Once a class is defined, we can create objects of the class, call the class methods, and access class attributes

myname = Name(first_name='Adam', middle_name='Alexander', last_name='Oppenheimer')
myname.print_name()
Adam Alexander Oppenheimer
myname.middle_name
'Alexander'

Objects of a class have the class as their type

type(myname)
__main__.Name

1.1.1 Comparing classes and dictionaries

You could think of classes like a type of dictionary with fixed keys and pre-written functions that work with those keys (this is a simplification, but might help clarify how they work)

myname_dict = {'first_name': 'Adam', 'middle_name': 'Alexander', 'last_name': 'Oppenheimer'}
myname_dict['first_name']
'Adam'
myname.first_name
'Adam'

1.2 A class for students

Classes can be nested - here, we nest the class Name inside a new class Student

class Student():
    def __init__(self, name, age, class_year):
        self.name = name
        self.age = age
        self.class_year = class_year

    def compute_approximate_birth_year(self):
        return 2024 - self.age
    
    def compute_approximate_graduation_year(self):
        return 2024 + (6 - self.class_year)
name1 = Name(first_name='Adam', middle_name='Alexander', last_name='Oppenheimer')
student1 = Student(name1, 26, 2022)
name2 = Name(first_name='Yutong', last_name='Zhong')
student2 = Student(name2, 25, 2021)
student1.name.print_name()
Adam Alexander Oppenheimer
student1.compute_approximate_birth_year()
1998

1.2.1 Defining new class attributes

student1.new_variable = 10
student1.new_variable
10

1.3 A class for classrooms

Now, we nest the class Student inside the new class Classroom

class Classroom():
    def __init__(self, class_number):
        if not isinstance(class_number, int):
            raise TypeError('class_number should be an integer')
        self.class_number = class_number
        self.students = []

    def add_student(self, student):
        if not isinstance(student, Student):
            raise TypeError('student should be a Student')
        self.students.append(student)

    def sort_students(self, order='last_name'):
        # Notice: use class attributes `first_name` and `last_name`
        if order == 'last_name':
            self.students = sorted(self.students, key=lambda a: a.name.last_name)
        elif order == 'first_name':
            self.students = sorted(self.students, key=lambda a: a.name.first_name)

    def print(self):
        # Notice: use class method `.print_name()`
        print('Class number:', self.class_number)
        print('Students:')
        for student in self.students:
            student.name.print_name()
python_course = Classroom(1)
python_course.add_student(student2)
python_course.add_student(student1)
python_course.print()
Class number: 1
Students:
Yutong Zhong
Adam Alexander Oppenheimer
python_course.sort_students(order='last_name')
python_course.print()
Class number: 1
Students:
Adam Alexander Oppenheimer
Yutong Zhong

2. Queues

An ordered list where variables are added then removed

2.1 Standard queues

What goes in first comes out first

import queue

a = queue.Queue()
a.put(1)
a.put(3)
a.put(2)
print(a.get())
print(a.get())
print(a.get())
1
3
2

Calling .get() on an empty queue causes the code to hang

a.get()
KeyboardInterrupt: 

2.2 Priority queues

Order based on some ranking (often the first element of a tuple). Read more about them for PA4.

b = queue.PriorityQueue()
b.put((1, 'hello'))
b.put((3, 'goodbye'))
b.put((2, 'waiting'))
print(b.get())
print(b.get())
print(b.get())
(1, 'hello')
(2, 'waiting')
(3, 'goodbye')

3. PA3 review

Discussion and review my solution