Topic #12b – More About Objects

More complexity

  • Let’s make a slightly more complex object.

  • What if I want to make MyStudents object.

  • It will basically just be an object that holds a list of my EnthusiasticStudents

  • It will also have the class name

But first… a convention

  • Let’s go look at out EnthusiasticStudent object and make one small change

     1class EnthusiasticStudent:
     2    '''
     3    Obv we'll include a nice comment at the top of the class to explain what it's for... right?!
     4
     5    This EnthusiasticStudent is being used to demonstrate how we can create our own Objects.
     6
     7    It's going to have a few attributes and some simple functions.
     8    '''
     9
    10    def __init__(self, first_name='John', last_name='Doe', student_num='000000000', current_avg=0):
    11        self._first_name = first_name
    12        self._last_name = last_name
    13        self._student_num = student_num
    14        self._current_avg = current_avg
    15
    16    def ask_for_higher_mark(self, howHigh):
    17        print('Hello Professor,\n\nMy name is ' + self._first_name + ' and I am in your CSCI 128 class. I feel that I deserve a higher mark on the last assignment. I would really like it if you could just give me a ' + str(howHigh) + '%. \n\nThanks,\n' + self._first_name + ' ' + self._last_name)
    18
    19
    20    def work_too_hard_on_assignment(self):
    21        # I left it blank. Add whatever code you want here. Be sure to delete the pass keyword when you do though
    22        pass
    23
    24
    25    def __repr__(self):
    26        '''
    27        A method which will return some string representation of the object. This will he handy for debugging and stuff.
    28        '''
    29        return 'First Name: ' + self._first_name + '\nlast_name: ' + self._last_name + '\nStudent Number: ' + self._student_num + '\nCurrent Average: ' + str(self._current_avg)
    30
    31
    32    def __eq__(self, anotherThing):
    33        '''
    34        A method to check if 2 EnthusiasticStudent are the same. What does it mean for 2 things to be the same?
    35        Well, WE get to make that up!
    36        (Although, we should pick something that makes sense...)
    37        '''
    38        return self._student_num == anotherThing.get_student_num()
    39
    40    # just a getter (see below)
    41    def get_first_name(self):
    42        return self._first_name
    43
    44    # just another getter (see below)
    45    def get_student_num(self):
    46        return self._student_num
    
  • I added underscores to each of the attributes

  • This makes them private
    • kinda…

Public/Private

  • Long story short…

  • Public attributes/methods are visible outside the class

  • Private attribute/methods are NOT visible outside the class

  • When we make something private, it’s like saying…
    • This attribute/method cannot be called anywhere else other than from within the code in the class.
      • James will now show you an example

  • Why do we care?

  • It’s all about encapsulation and design

  • A well designed program will probably have public and private attribute/methods

  • In Python, the convention for our private variables is to put an underscore in front.

  • The idea is, if I’m using the object someone else wrote, I don’t need to know about what I don’t need to know about…

  • Let me put it this way.
    • You have all used lists
      • We know how to use them

      • We don’t know how they work

      • We don’t know what attributes they have

      • But that’s OK

  • Or how about this?
    • Imagine a car

    • Do you know how to drive a car?
      • gas, break, steer

    • Does the way you interface with the car matter if, say, the car is electric or gas?

    • A gas and electric car are built very different on the inside, but that didn’t really impact the way you interface with the object.

  • Don’t worry too much if the point is still a little lost on you, it will get cleared in CSCI 162.

Getters/Setters

  • So how do we interface with the attributes if we make them all private?

  • Getters and setters!

  • It’s so simple it’s silly really

  • Here is an example with getting/setting _student_num

    1def get_student_num(self):
    2    return self._student_num
    3
    4def set_student_num(self, student_num):
    5    self._student_num = student_num
    
  • Does it feel silly doing this?

  • Yes, good, you’re normal

  • But again, motivation for this will reallllly come next semester.
    • Teaser: We can control how the attributes are interacted with.

    • We can enforce data integrity rules
      • Eg. Ensure all Student Numbers are 9 chars long.

Activity

  • Try this example and see what happens when you change a private attribute without control on the modification.

1a_student = EnthusiasticStudent("Bob", "Ross", "007")
2
3# A user manually changes the private attibute
4a_student._student_num = 5
5
6print(a_student)
  • What is the problem?

  • How can set_student_num() help us?

MyStudents

  • Ok, we want an object to hold onto EnthusiasticStudent objects

  • What attributes do we want?
    • Name

    • List of the EnthusiasticStudents

    1class MyStudents:
    2
    3
    4    def __init__(self, name='DEFAULT_NAME'):
    5        self._class_name = name
    6        self._list_of_students = []
    
  • That was easy

  • Notice that we did not give the constructor a parameter for the self._list_of_students attribute. We don’t need to!

  • Let’s write a method to add a student to the class

    1def add_student(self, fN, lN, sN, avg):
    2    a_student = EnthusiasticStudent(fN, lN, sN, avg)
    3    self._list_of_students.append(a_student)
    
  • Let’s write a method to search the list of EnthusiasticStudents for a student with a specific first name. Return True if it’s in the list, False otherwise.

    1def find_student(self, fName):
    2    for student in self._list_of_students:
    3        if fName == student.get_first_name():    # this assumes we wrote a getter/setter
    4            return True
    5    return False
    
  • __repr__
    • How should we convert the MyStudents object into a string?

    1    def __repr__(self):
    2        s = self._class_name + '\n'
    3        for student in self._list_of_students:
    4            # Below we just convert the student to a string.
    5            # the str(student) will automatically call the
    6            # the student's __repr__ method.
    7            s += str(student) + '\n\n'    # Will work because we have a __repr__ for EnthusiasticStudent written
    8
    9        return s
    

Putting it Together

 1# Only need these if using multiple files
 2#from EnthusiasticStudent import *
 3#from MyStudents import *
 4
 5some_class = MyStudents('CSCI 161')
 6some_class.add_student('Greg', 'Allen', '54321', 98)
 7some_class.add_student('Bob','Smith', '12345', 50)
 8print(some_class.find_student('Bob'))
 9
10print(some_class)

The END!

  • Thank you all for staying until the end!

  • You now all the basic about programming.

  • There are lot of things that we could cover, but for that you should go in CS!