Classes#

Q&A

Q: Why do loops exist?
A: To allow you to repeat code again and again without having to copy + paste very similar code over and over again and change one little bit.

Q: How to know when to use certain methods?
A: The “real” answer is ….you get famililar over time. The answer for when starting out is: if it feels like you’re doing a task that someone else has also probably wanted to do with this variable type (i.e. add something to a list), it’s worth pausing and looking up if there’s already a method to accomplish what you want to do before writing the code yourself. On exams, you need to know append() and items(). All of the others will be described, but you’ll need to know how to then use it.

Q: You mentioned that “my_variable.function_call() acts like function_call(my_variable).” Why do we have methods if they work this way as well?
A: Because methods have the addded feature that they “belong” to an object. This keeps things organized (you’ll see this more today!) and necessitates that they are syntactically distinct (meaning my_variable.method() vs function(my_variable).

Course Announcements

Due this week:

  • CL5 due Fri

  • Mid-course survey “due” (for extra credit) Sunday - link also on Canvas assignment

Classes Overview#

  • Objects

  • Classes

    • Attributes

    • Methods

  • Instances

    • __init__

…and f-strings

Object-oriented programming (OOP) is a programming paradigm in which code is organized around objects. Python is an OOP programming langauge.

Objects#

Objects are an organization of data (called attributes), with associated code to operate on that data (functions defined on the objects, called methods).
from datetime import date
my_date = date(year=1988, month=9, day=29)
print(my_date)
type(my_date)

Attributes#

Attributes look up & return information about the object.

attributes maintain the object’s state, simply returning information about the object to you

my_date.day
my_date.year

Methods#

These are functions that belong to and operate on the object directly.

methods modify the object’s state

# Method to return what day of the week the date is
my_date.weekday()
my_date.weekday?

Activity: ~Methods~ Objects#

Complete the Google Form questions here: https://forms.gle/xv313353UdSNCVuL8

Feel free to chat with and ask questions of your neighbors!

Objects Summary#

  • Objects allow for data (attributes) and functions (methods) to be organized together

    • methods operate on the object type (modify state)

    • attributes store and return information (data) about the object (maintain state)

  • dir() returns methods & attributes for an object

  • Syntax:

    • obj.method()

    • obj.attribute

  • date and datetime are two types of objects in Python

dir(my_date)

class#

  • a blueprint for creating objects

  • contain attributes & methods

    • attributes: variables attached to the object

    • methods: functions attached to the object

review: Dog#

[Note: this is what the textbook/videos walked through in detail.]

class Dog():
    # class attribute - value will be the same for every Dog
    sound = 'Woof'
    
    # instance attribute
    def __init__(self, name, breed):
        self.name = name
        self.breed = breed

    # method
    def speak(self, n_times=2):
        return self.sound * n_times
# creating an instance
my_dog = Dog('Lexi', 'Italian Greyhound')
# accessing attributes
my_dog.sound
my_dog.name
my_dog.breed
# methods - with default
my_dog.speak()
# method - other value for n_times parameter
my_dog.speak(4)

Code Style: Classes#

  • CapWords for class names

  • one blank line between methods/functions

Good Code Style

class MyClass():
    
    def __init__(self, name, email, score):
        self.name = name
        self.email = email
        self.score = score
    
    def check_score(self):        
        if self.score <= 65:
            return self.email
        else:
            return None
cogs18 = MyClass('shannon', 'sellis@ucsd.edu', 60)
cogs18.check_score()

Code Style to Avoid

class my_class(): # uses snake case for name
    def __init__(self, name, email, score):
        self.name = name
        self.email = email
        self.score = score   # no blank lines between methods  
    def check_score(self):        
        if self.score <= 65:
            return self.email
        else:
            return None

Activity: Instances#

Complete the Google Form questions here: https://forms.gle/BA9zC1zjiviqGHst8

Feel free to chat with and ask questions of your neighbors!

Example: ProfCourses()#

Let’s put a lot of these concepts together in a more complicated example…

What if we wanted some object type that would allow us to keep track of Professor Ellis’ Courses? Well…we’d want this to work for any Professor, so we’ll call it ProfCourses.

We would likely want an object type and then helpful methods that allow us to add a class to the course inventory and to compare between courses.

[This is also worked in the textbook, but was not required reading/discussed in the video.]

class ProfCourses():
    
    # create three instance attributes
    def __init__(self, prof):
        self.n_courses = 0
        self.courses = []
        self.prof = prof
ellis_courses = ProfCourses('Ellis')
print(ellis_courses.n_courses)
print(ellis_courses.prof)

add_class() method

class ProfCourses():
    
    def __init__(self, prof):
        self.n_courses = 0
        self.courses = []
        self.prof = prof
    
    # add method that will add courses as a dictionary
    # to our attribute (courses)...which is a list
    def add_course(self, course_name, quarter, n_students):
        
        self.courses.append({'course_name': course_name, 
                             'quarter' : quarter, 
                             'n_students': n_students})
        # increase value store in n_courses
        # by 1 any time a class is added
        self.n_courses += 1
# create ellis_courses
ellis_courses = ProfCourses('Ellis')

# add a class
ellis_courses.add_course('COGS18', 'fa20', 363)

# see output
print(ellis_courses.courses)
ellis_courses.n_courses

compare() method

class ProfCourses():
    
    def __init__(self, prof):
        self.n_courses = 0
        self.courses = []
        self.prof = prof
    
    def add_course(self, course_name, quarter, n_students):
        
        self.courses.append({'course_name': course_name,
                             'quarter' : quarter,
                             'n_students': n_students})
        self.n_courses += 1
            
    # add method to compare values in courses
    def compare(self, attribute, direction='most'):
    
        fewest = self.courses[0]
        most = self.courses[0] 
        
        for my_course in self.courses:
            if my_course[attribute] <= fewest[attribute]:
                fewest = my_course
            elif my_course[attribute] >= most[attribute]:
                most = my_course
                
        if direction == 'most':
            output = most
        elif direction == 'fewest':
            output = fewest

        return output
# create ellis_courses
ellis_courses = ProfCourses('Ellis')

# add a bunch of classes
ellis_courses.add_course('COGS18', 'fa20', 363)
ellis_courses.add_course('COGS108', 'fa20', 447)
ellis_courses.add_course('COGS18', 'su20', 88)
ellis_courses.add_course('COGS108', 'sp20', 469)

# see the courses
print(ellis_courses.n_courses)
ellis_courses.courses
# make comparison among all courses
# returns the class with the most students
ellis_courses.compare('n_students')
# return the class with the fewest students
ellis_courses.compare('n_students', 'fewest')

extending the functionality of the compare() method

class ProfCourses():
    
    def __init__(self, prof):
        self.n_courses = 0
        self.courses = []
        self.prof = prof
    
    def add_course(self, course_name, quarter, 
                   n_students, n_exams, n_assignments):
        
        # add in additional key-value pairs
        self.courses.append({'course_name': course_name,
                             'quarter' : quarter,
                             'n_students': n_students,
                             'n_exams' : n_exams,
                             'n_assignments' : n_assignments}) # <-- changes made in courses
        self.n_courses += 1
             
    def compare(self, attribute, direction='most'):
    
        fewest = self.courses[0]
        most = self.courses[0] 
        
        for my_course in self.courses:
            if my_course[attribute] <= fewest[attribute]:
                fewest = my_course
            elif my_course[attribute] >= most[attribute]:
                most = my_course
                
        if direction == 'most':
            output = most
        elif direction == 'fewest':
            output = fewest

        return output
# create ellis_courses
ellis_courses = ProfCourses('Ellis')

# add a bunch of classes
ellis_courses.add_course('COGS18', 'fa20', 363, 2, 5)
ellis_courses.add_course('COGS108', 'fa20', 447, 0, 6)
ellis_courses.add_course('COGS18', 'su20', 88, 3, 5)
ellis_courses.add_course('COGS108', 'sp20', 469, 0, 6)
ellis_courses.add_course('COGS108', 'sp19', 825, 0, 5)
ellis_courses.add_course('COGS18', 'fa19', 301, 2, 4)
ellis_courses.add_course('COGS18', 'wi22', 355, 2, 4)
ellis_courses.add_course('COGS18', 'sp23', 355, 2.5, 5)
ellis_courses.add_course('COGS137', 'fa23', 70, 2, 3)
ellis_courses.add_course('COGS169', 'fa23', 58, 2, 0)
ellis_courses.add_course('COGS108', 'wi24', 656, 0, 4)
ellis_courses.add_course('COGS18', 'sp24', 621, 2.5, 5)
ellis_courses.add_course('COGS137', 'fa24', 100, 0, 3)
ellis_courses.add_course('COGS169', 'fa24', 52, 2, 0)
ellis_courses.add_course('COGS18', 'sp25', 630, 2.5, 5)

# see the courses
print(ellis_courses.n_courses)
# return the class with the most exams
ellis_courses.compare('n_exams', 'most')
# return the class with the fewest assignments
ellis_courses.compare('n_assignments', 'fewest')

Activity: ProfCourses Understanding Check#

Complete the Google Form questions here: https://forms.gle/mXX1veAdvDgriApP6

Feel free to chat with and ask questions of your neighbors!

Improving & updating this code

  • account for ties in compare()

  • edit code in compare() use max() and min() instead of looping

  • add a method to put dictionary in time order

  • etc.

Classes Review#

  • class creates a new class type

    • names tend to use CapWords case

    • can have attributes (including instance attributes) and methods

      • obj.attribute accesses data stored in attribute

      • obj.method() carries out code defined within method

  • instance attributes defined with __init__

    • __init__ is a reserved method in Python

    • This “binds the attributes with the given arguments”

    • self refers to current instance

  • to create an object (instance) of a specified class type (ClassType):

    • object_name = ClassType(input1, input2)

    • self is not given an input when creating an object of a specified class

String Concatenation#

(revisited)

# string concatenation - old way
name = 'Shannon'
name2 = 'Ellis'

name + ' ' + name2

f-Strings#

You can put variables inside of a string by using f-strings.

To create an f-string you will need to put f", an f with double quotation marks infront of it.

Then put any variable name using curly braces {}

Lastly, end your statement with the remaining "


# f strings - new way
f"{name} {name2}"
class CollegeStudent():
    def __init__(self, name, age, major, college):
        self.name = name
        self.age = age
        self.major = major
        self.college = college

    def introduction(self):
        return f"Hi, my name is {self.name}, and I am {self.age} years old. I study {self.major} at {self.college}."
my_student = CollegeStudent('Shannon', 37, 'Biology', "King's College")
my_student.name
my_student.college
my_student.introduction()