Difference between revisions of "OPS435 Python Lab 6"

From CDOT Wiki
Jump to: navigation, search
(PART 1 - Creating a Class)
 
(22 intermediate revisions by 4 users not shown)
Line 1: Line 1:
 +
<font color='red'>
 +
'''** DO NOT USE - TO BE UPDATED FOR CENTOS 8.0 **'''
 +
</font>
 
= LAB OBJECTIVES =
 
= LAB OBJECTIVES =
:Python is an object oriented programming language. Python uses the concept of "objects" to store data(attributes) and code(methods) efficiently for later use. By using objects, programming languages gain the advantage of making large/complex programs into smaller and modular objects, which can be used or shared with other code. In Python, almost everything that we have used is actually an object with a specific purpose, however starting in this lab we will create our own objects, and investigate different ways to use them.
+
* Create new type of objects using the Class construct and investigate different ways in using them.
 +
 
 +
:Python is an object oriented programming language. Python uses the concept of "object" to store data(attributes) and code(methods) efficiently for later use. By using objects, programming languages gain the advantage of making large/complex programs into smaller and modular codes, which can be used or shared with other users/programs. In Python, almost everything that we have used is actually an object with a specific purpose, however starting in this lab we will create our own objects, and investigate different ways to use them.
  
  
  
 
== PYTHON REFERENCE ==
 
== PYTHON REFERENCE ==
:In previous labs, you have been advised to make notes and use online references. This also relates to learning about objected oriented programming to help becoming "overwhelmed" with the volume of information in this lab.  
+
:In previous labs, you have been advised to make notes and use online references. This also apply to learning about object oriented programming.  
  
:Below is a table with links to useful online Python reference sites (by category). You may find these references useful when performing assignments and labs.
+
:Below is a table with links to online Python document for Classes and objects. You should study the information given below and make sure you understand the key concepts introduced and discussed before start working on this lab.
  
 
{| class="wikitable" | style="margin-left:20px; border: 2px solid black;"
 
{| class="wikitable" | style="margin-left:20px; border: 2px solid black;"
Line 16: Line 21:
 
|-  style="background-color:white;border:none;"
 
|-  style="background-color:white;border:none;"
 
| style="border: 2px solid black;" valign="top"|   
 
| style="border: 2px solid black;" valign="top"|   
:Handling Errors &amp; Exceptions
+
:Using Classes
 
| style="border: 2px solid black;" valign="top"|   
 
| style="border: 2px solid black;" valign="top"|   
:[https://docs.python.org/3/tutorial/errors.html Errors &amp; Exceptions]
+
:[https://docs.python.org/3/tutorial/classes.html Classes]
  
 
|-  style="background-color:white;border:none;"
 
|-  style="background-color:white;border:none;"
 
| style="border: 2px solid black;" valign="top"|   
 
| style="border: 2px solid black;" valign="top"|   
:Built-in Exceptions
+
:Classes and Objects
 
| style="border: 2px solid black;" valign="top"|   
 
| style="border: 2px solid black;" valign="top"|   
:[https://docs.python.org/3/library/exceptions.html Built-in Exceptions]
+
:[http://greenteapress.com/thinkpython2/html/thinkpython2016.html Think Python Chapter 15]
  
 
|-  style="background-color:white;border:none;"
 
|-  style="background-color:white;border:none;"
 
| style="border: 2px solid black;" valign="top"|   
 
| style="border: 2px solid black;" valign="top"|   
:Lists
+
:Classes and functions
 
| style="border: 2px solid black;" valign="top"|   
 
| style="border: 2px solid black;" valign="top"|   
:[https://docs.python.org/3/tutorial/introduction.html#lists Lists]
+
:[http://greenteapress.com/thinkpython2/html/thinkpython2017.html Think Python Chapter 16]
  
 
|-  style="background-color:white;border:none;"
 
|-  style="background-color:white;border:none;"
 
| style="border: 2px solid black;" valign="top"|   
 
| style="border: 2px solid black;" valign="top"|   
:Dictionaries
+
:Classes and methods
 
| style="border: 2px solid black;" valign="top"|   
 
| style="border: 2px solid black;" valign="top"|   
:[https://docs.python.org/3/tutorial/datastructures.html#dictionaries Dictionaries]
+
:[http://greenteapress.com/thinkpython2/html/thinkpython2018.html Think Python Chapter 17]
  
|-  style="background-color:white;border:none;"
 
| style="border: 2px solid black;" valign="top"| 
 
:Using Classes
 
| style="border: 2px solid black;" valign="top"| 
 
:[https://docs.python.org/3/tutorial/classes.html Classes]
 
 
|}
 
|}
 +
 +
== Key Concepts related to Python Class and Object ==
 +
* Programmer-defined types
 +
* Class Object
 +
* Class methods: __init__, __str__, etc
 +
* Class instance: attributes and methods
 +
* Object instantiation
 +
* Object Attributes
 +
* Pure Function
 +
* Scopes and Namespaces: local, nonlocal, and global
 +
* Class definition syntax
 +
* Class and Instance variables
 +
* Iterators and Generators
 +
 +
* Operator overloading
  
 
= INVESTIGATION 1: Creating Classes =
 
= INVESTIGATION 1: Creating Classes =
Line 49: Line 64:
  
 
== PART 1 - Creating a Class ==
 
== PART 1 - Creating a Class ==
:The class that is written in Python can contain variables, functions, code, but none of the code is executed or run until the class is used to create the object. Remember that the class is a blueprint for how your object will work, the object that will be created is what will actually be running the code. This of a class in the same way as a function definition, the function doesn't run until it's executed, code inside classes don't run until the are made into objects.  
+
:Each object of a class that we write in Python can contain variables, functions, code, but none of the code is executed or run until the class is used to create an object. Remember that the class is a blueprint for how your object will work, the object that will be created is what will actually be running the code. This part of a class works in the same way as a function definition, the function doesn't run until it's executed, code inside classes doesn't run until they are made into objects.  
  
 
:'''Perform the Following Steps:'''
 
:'''Perform the Following Steps:'''
:#Launch your Centos VM, open a shell terminal (as a regular user) and start a new ipython3 session:<source lang="python">
+
:#Create a new python script in the lab6 directory:<source lang="bash">
ipython3
+
cd ~/ops435/lab6
</source>
+
vim ~/ops435/lab6/student.py
:#Create a new python script in the lab6 directory:<source lang="python">
 
%cd ~/ops435/lab6
 
%vim ~/ops435/lab6/student.py
 
 
</source>
 
</source>
 
:#Place the following content inside the new python script and save it. Read through this script and the comments inside.<source lang="python">
 
:#Place the following content inside the new python script and save it. Read through this script and the comments inside.<source lang="python">
Line 93: Line 105:
  
 
</source>
 
</source>
:# This is how you give the class a name, now when you need to create a new Student object we know the class is called Student. '''Everything''' indented underneath the '''class Student:''' will be apart of the class.
+
:# This is how you give the class a name, now when you need to create a new Student object we know the class is called Student. '''Everything''' indented underneath the '''class Student:''' will be a part of the class.
 
:# Next indented under the class is the __init__() method. This works similarly to a function, it contains code indented underneath it, that code is executed when you call the function. But __init__() is a special method, instead of manually calling this method, it will automatically be executed when we create a object. Inside the __init__() we create variables(object attributes), these are created using '''self.name''', where '''name''' is the name of the attribute. The '''self.''' portion before the variable name is to let the class know that this variable can be accessed from anywhere inside the class and outside of the class, as a public attribute. Lets come back to this later.<source lang="python">
 
:# Next indented under the class is the __init__() method. This works similarly to a function, it contains code indented underneath it, that code is executed when you call the function. But __init__() is a special method, instead of manually calling this method, it will automatically be executed when we create a object. Inside the __init__() we create variables(object attributes), these are created using '''self.name''', where '''name''' is the name of the attribute. The '''self.''' portion before the variable name is to let the class know that this variable can be accessed from anywhere inside the class and outside of the class, as a public attribute. Lets come back to this later.<source lang="python">
    def __init__(self, name, number):
+
def __init__(self, name, number):
        self.name = name
+
    self.name = name
        self.number = number
+
    self.number = number
        self.courses = {}
+
    self.courses = {}
 
</source>
 
</source>
 
:# The next method definition prints out variables self.name and self.number, both of these variables were set in the __init__() method. Normally creating variables inside a function means they can only be accessed inside of that specific function. But classes give us the ability to share data throughout the class with all other objects. Place '''self.''' before the variable name to allow that variable to be shared with different functions, these variables are called public attributes. However, as we will soon come to see this variable is only shared within a single instance of the class(more on this to come). <source lang="python">
 
:# The next method definition prints out variables self.name and self.number, both of these variables were set in the __init__() method. Normally creating variables inside a function means they can only be accessed inside of that specific function. But classes give us the ability to share data throughout the class with all other objects. Place '''self.''' before the variable name to allow that variable to be shared with different functions, these variables are called public attributes. However, as we will soon come to see this variable is only shared within a single instance of the class(more on this to come). <source lang="python">
    # Display student name and number
+
# Display student name and number
    def displayStudent(self):
+
def displayStudent(self):
        print('Student Name: ' + self.name)
+
    print('Student Name: ' + self.name)
        print('Student Number: ' + self.number)
+
    print('Student Number: ' + self.number)
 
</source>
 
</source>
:# This next method accepts some arguments. The first argument of the method is '''self''', this is a required syntax for making methods inside of a class, and allows the method to access any variables you created/saved in the class previously, such as, '''self.courses'''. This method will take two additional arguments, course, and grade. The method will then store these inside a dictionary '''self.courses''', with the key being '''course''' and the value being '''grade'''.<source lang="python">
+
:# This next method accepts some arguments. The first argument of the method is '''self''', this is required syntax for making methods inside of a class, and allows the method to access any variables you created/saved in the class previously, such as, '''self.courses'''. This method will take two additional arguments: course and grade. The method will then store these inside a dictionary '''self.courses''', with the key being '''course''' and the value being '''grade'''.<source lang="python">
# Add a new course and grade to students record
+
# Add a new course and grade to students record
    def addGrade(self, course, grade):
+
def addGrade(self, course, grade):
        self.courses[course] = grade
+
    self.courses[course] = grade
 
</source>
 
</source>
 
:# This final method will do a bit of calculations. It will get the average of all values found inside the dictionary, add them up, and divide them by the number of values. When it finishes, the method will print out a message with the GPA of the student inside.<source lang="python">
 
:# This final method will do a bit of calculations. It will get the average of all values found inside the dictionary, add them up, and divide them by the number of values. When it finishes, the method will print out a message with the GPA of the student inside.<source lang="python">
    # Calculate the grade point average of all courses and display it
+
# Calculate the grade point average of all courses and display it
    def displayGPA(self):
+
def displayGPA(self):
        gpa = 0.0
+
    gpa = 0.0
        for course in self.courses.keys():
+
    for course in self.courses.keys():
            gpa = gpa + self.courses[course]
+
        gpa = gpa + self.courses[course]
        print('GPA of student ' + self.name + ' is ' + str(gpa / len(self.courses)))
+
    print('GPA of student ' + self.name + ' is ' + str(gpa / len(self.courses)))
 
</source>
 
</source>
:# Now that the class has been broken down, the code inside is simple on it's own, but what does it mean when it all works together. So before you can use a class, we must create a new object. A single class can create many objects, not just a single object. This class will be used to create lots of different student objects, each object will be created using the blue print of the class, but they will all be separate and contain separate data to store each and every students data. Try to think of an object as any other python data structure(list, set, dictionary), you can create multiple dictionaries and store difference data inside, even if some of the data is the same.
+
:# Now that the class has been broken down, the code inside is simple on it's own, but what does it mean when it all works together? Before you can use a class, we must create a new object. A single class description can be used to create as many objects as you like, not just a single object. Our '''Student''' class will be used to create lots of different student objects, each object will be created using the blueprint of the class, but they will all be separate and contain separate data to store each and every student's data. Try to think of an object as any other python data structure (list, set, dictionary): you can create multiple dictionaries and store different data inside, even if some of the data is the same.
:# Import the python script into your ipython environment:<source lang="python">
+
:# In a new file, import the Student class:<source lang="python">
 
from student import Student
 
from student import Student
 
</source>
 
</source>
Line 126: Line 138:
 
# Creates an instance of the Student class, it will be separate from all other objects created with the Student class:
 
# Creates an instance of the Student class, it will be separate from all other objects created with the Student class:
 
student1 = Student('John', '013454900')
 
student1 = Student('John', '013454900')
student1.addGrade('uli101', 4.0)
 
student1.addGrade('ops235', 3.5)
 
student1.addGrade('ops435', 3.0)
 
 
</source>
 
</source>
:# Now that the object '''student1''' has been created, look closely at the components inside the object. This is a look into the objects '''namespace''':<source lang="python">
+
:# Have a look at the contents of the object student1:<source lang="python">
dir(student1)
+
print(student1.name)
</source>
+
print(student1.number)
:# Notice anything familiar in here? This will display all attributes(name, number, courses) that were created with '''self.variableName''', it also shows all the methods(displayStudent, displayGPA, addCourse) that were created too. Take a closer look at some of these different attributes and methods.<source lang="python">
+
print(student1.courses)
student1.name
 
student1.number
 
student1.courses
 
 
student1.displayStudent()
 
student1.displayStudent()
 
</source>
 
</source>
 
:# Before going further with '''student1''', lets create a second object, to demonstrate that these are different data structures:<source lang="python">
 
:# Before going further with '''student1''', lets create a second object, to demonstrate that these are different data structures:<source lang="python">
 
student2 = Student('Jessica', '023384103')
 
student2 = Student('Jessica', '023384103')
student2.name
+
</source>
student2.number
+
:# Take a closer look at some of these different attributes and methods.<source lang="python">
student2.courses
+
print(student2.name)
 +
print(student2.number)
 +
print(student2.courses)
 
student2.displayStudent()
 
student2.displayStudent()
 
</source>
 
</source>
Line 153: Line 161:
  
 
# Add new courses for student2
 
# Add new courses for student2
student2 = Student('Jessica', '023384103')
 
 
student2.addGrade('ipc144', 4.0)
 
student2.addGrade('ipc144', 4.0)
 
student2.addGrade('cpp244', 4.0)
 
student2.addGrade('cpp244', 4.0)
 
</source>
 
</source>
 
:# Investigate what has changed in each object:<source lang="python">
 
:# Investigate what has changed in each object:<source lang="python">
student1.name
+
print(student1.name)
student1.courses
+
print(student1.courses)
student2.name
+
print(student2.name)
student2.courses
+
print(student2.courses)
 
</source>
 
</source>
 
:# The method '''addGrade()''' changes the '''self.courses''' dictionary. But both student1 and student2 have their OWN courses dictionary.
 
:# The method '''addGrade()''' changes the '''self.courses''' dictionary. But both student1 and student2 have their OWN courses dictionary.
 
:# Once an object is created the attributes inside may be modified externally. Though you may need to be careful, if a value is a string, and you change it to another type such as a integer or a list, it's possible the class was not designed to deal with the different type and may throw a error when you run a method. For example, changing the name to a integer would break the displayStudent method, because it would try and concatenate strings and integers(maybe the method should be written better.<source lang="python">
 
:# Once an object is created the attributes inside may be modified externally. Though you may need to be careful, if a value is a string, and you change it to another type such as a integer or a list, it's possible the class was not designed to deal with the different type and may throw a error when you run a method. For example, changing the name to a integer would break the displayStudent method, because it would try and concatenate strings and integers(maybe the method should be written better.<source lang="python">
 
# student1.name is a string like any other
 
# student1.name is a string like any other
student1.name
+
print(student1.name)
 
student1.name = 'Jack'
 
student1.name = 'Jack'
student1.name
 
 
print(student1.name)
 
print(student1.name)
 
len(student1.name)
 
len(student1.name)
 
</source>
 
</source>
 
:# The final part to creating objects is understanding how to pass values into newly created objects, such as, '''student2 = Student('Jessica', '023384103')'''. How did it know that Jessica is the name instead of the long string of numbers? This is done when the class is written, inside the __init__() method. Look at the arguments used for in the __init__ definition:<source lang="python">
 
:# The final part to creating objects is understanding how to pass values into newly created objects, such as, '''student2 = Student('Jessica', '023384103')'''. How did it know that Jessica is the name instead of the long string of numbers? This is done when the class is written, inside the __init__() method. Look at the arguments used for in the __init__ definition:<source lang="python">
    def __init__(self, name, number):
+
def __init__(self, name, number):
        self.name = name
+
    self.name = name
        self.number = number
+
    self.number = number
        self.courses = {}
+
    self.courses = {}
 
</source>
 
</source>
 
:# First was self, but this is required and we can ignore this for now. Next is '''name''', this is the classes first argument when we instantiate(create) it, the second argument is '''number'''.<source lang="python">
 
:# First was self, but this is required and we can ignore this for now. Next is '''name''', this is the classes first argument when we instantiate(create) it, the second argument is '''number'''.<source lang="python">
Line 184: Line 190:
  
 
=== Create a Python Script Demonstrating Classes ===
 
=== Create a Python Script Demonstrating Classes ===
:# The following python script is broken. It has two major problems to fix and one new feature to add: first problem is providing the student number as an integer causes an error(TypeError) when displayStudent() is run, second problem is in displayGPA() may divide by zero erorr(ZeroDivisionError) if no courses are added to the dictionary or the grades added to the dictionary are 0.0 floats. Finally, you will add a new method to this class that prints out a formatted list of all courses the student has taken.
+
:# The following python script is broken. It has two major problems to fix and one new feature to add: first problem is providing the student number as an integer causes an error(TypeError) when displayStudent() is run, second problem is in displayGPA() may divide by zero(ZeroDivisionError) if no courses are added to the dictionary or the grades added to the dictionary are 0.0 floats. Finally, you will add a new method to this class that prints out a formatted list of all courses the student has taken.
 
:#Create the '''~/ops435/lab6/lab6a.py''' script.
 
:#Create the '''~/ops435/lab6/lab6a.py''' script.
 
:#Use the following as a template(warning this is NOT the same as student.py):<source lang="python">
 
:#Use the following as a template(warning this is NOT the same as student.py):<source lang="python">
Line 246: Line 252:
 
::*The script should contain no errors
 
::*The script should contain no errors
 
:::'''Sample Run 1:'''<source lang="python">
 
:::'''Sample Run 1:'''<source lang="python">
python3 lab6a.py
+
./lab6a.py
 
Student Name: John
 
Student Name: John
 
Student Number: 013454900
 
Student Number: 013454900
Line 256: Line 262:
 
['cpp244', 'ipc144']
 
['cpp244', 'ipc144']
 
</source>
 
</source>
:::'''Sample Run 2 (import into ipython3):'''<source lang="python">
+
:::'''Sample Run 2 (with import):'''<source lang="python">
 
from lab6a import Student
 
from lab6a import Student
  
Line 266: Line 272:
  
 
student1.displayStudent()
 
student1.displayStudent()
'Student Name: Jack\nStudent Number: 931686102'
+
# Will print: 'Student Name: Jack\nStudent Number: 931686102'
  
 
student1.displayGPA()
 
student1.displayGPA()
'GPA of student Jack is 1.0'
+
# Will print: 'GPA of student Jack is 1.0'
  
 
student1.displayCourses()
 
student1.displayCourses()
['ops535']
+
# Will print: ['ops535']
  
 
student2 = Student('Jen', 987654321)
 
student2 = Student('Jen', 987654321)
 
student2.addGrade('uli101', 0.0)
 
  
 
student2.displayGPA()
 
student2.displayGPA()
'GPA of student Jen is 0.0'
+
# Will print: 'GPA of student Jen is 0.0'
  
 
student2.displayCourses()
 
student2.displayCourses()
[]
+
# Will print: []
 
</source>
 
</source>
::3. Exit the ipython3 shell, download the checking script and check your work. Enter the following commands from the bash shell.<source lang="bash">
+
::3. Download the checking script and check your work. Enter the following commands from the bash shell.<source lang="bash">
 
cd ~/ops435/lab6/
 
cd ~/ops435/lab6/
 
pwd #confirm that you are in the right directory
 
pwd #confirm that you are in the right directory
Line 290: Line 294:
 
python3 ./CheckLab6.py -f -v lab6a
 
python3 ./CheckLab6.py -f -v lab6a
 
</source>
 
</source>
::4. Before proceeding, make certain that you identify any and all errors in lab6a.py. When the checking script tells you everything is OK before proceeding to the next step.
+
::4. Before proceeding, make certain that you identify all errors in lab6a.py. When the checking script tells you everything is OK - proceed to the next step.
 
<br><br>
 
<br><br>
  
Line 304: Line 308:
 
# What happens if you try and make a copy of an object?
 
# What happens if you try and make a copy of an object?
 
# When does the __init__() method get executed?
 
# When does the __init__() method get executed?
# What is an attribute? How to you create an attribute?
+
# What is an attribute? How do you create an attribute?
 
# What is a method?
 
# What is a method?
 
# What is the difference between a method and a function?
 
# What is the difference between a method and a function?
 
# What is self used for in an object?
 
# What is self used for in an object?
 
# What does it mean to instantiate an object?
 
# What does it mean to instantiate an object?
# Import the Student class into ipython3, instantiate some objects, and try changing different attributes.
+
# Import the Student class into ipython3, instantiate some objects, and try changing different attributes, and adding new attributes.
 
# Make a copy of lab6a.py called lab6practice.py, make the Student class accept another argument called program. When you create the new object: student = Student('name', '123456789', 'CTY'). Can you print the new students program out with student.program?
 
# Make a copy of lab6a.py called lab6practice.py, make the Student class accept another argument called program. When you create the new object: student = Student('name', '123456789', 'CTY'). Can you print the new students program out with student.program?
# Create a new method in lab6practice.py that checks to make sure the program is either "CTY" or "CNS", if it's not one of these, change the value to "unknown".
+
# Create a new method in lab6practice.py that checks to make sure the program is either "CTY" or "CNS", if it's not one of these, change the value to "unknown". Make sure the attribute is changed after your object is created.
  
  
  
 
[[Category:OPS435-Python]]
 
[[Category:OPS435-Python]]

Latest revision as of 08:27, 21 January 2020

** DO NOT USE - TO BE UPDATED FOR CENTOS 8.0 **

LAB OBJECTIVES

  • Create new type of objects using the Class construct and investigate different ways in using them.
Python is an object oriented programming language. Python uses the concept of "object" to store data(attributes) and code(methods) efficiently for later use. By using objects, programming languages gain the advantage of making large/complex programs into smaller and modular codes, which can be used or shared with other users/programs. In Python, almost everything that we have used is actually an object with a specific purpose, however starting in this lab we will create our own objects, and investigate different ways to use them.


PYTHON REFERENCE

In previous labs, you have been advised to make notes and use online references. This also apply to learning about object oriented programming.
Below is a table with links to online Python document for Classes and objects. You should study the information given below and make sure you understand the key concepts introduced and discussed before start working on this lab.
Category Resource Link
Using Classes
Classes
Classes and Objects
Think Python Chapter 15
Classes and functions
Think Python Chapter 16
Classes and methods
Think Python Chapter 17

Key Concepts related to Python Class and Object

  • Programmer-defined types
  • Class Object
  • Class methods: __init__, __str__, etc
  • Class instance: attributes and methods
  • Object instantiation
  • Object Attributes
  • Pure Function
  • Scopes and Namespaces: local, nonlocal, and global
  • Class definition syntax
  • Class and Instance variables
  • Iterators and Generators
  • Operator overloading

INVESTIGATION 1: Creating Classes

In this first investigation you will be introduced to classes. A class is a blue print to creating an object, first we write what we want the object to contain inside the class, then we can instantiate(create the object) by providing the class type. Once an object is created, interacting with the object will look very familiar, because you have been using objects throughout the entire course, the only difference is these object will be created by you.

PART 1 - Creating a Class

Each object of a class that we write in Python can contain variables, functions, code, but none of the code is executed or run until the class is used to create an object. Remember that the class is a blueprint for how your object will work, the object that will be created is what will actually be running the code. This part of a class works in the same way as a function definition, the function doesn't run until it's executed, code inside classes doesn't run until they are made into objects.
Perform the Following Steps:
  1. Create a new python script in the lab6 directory:
    cd ~/ops435/lab6
    vim ~/ops435/lab6/student.py
  2. Place the following content inside the new python script and save it. Read through this script and the comments inside.
    #!/usr/bin/env python3
    
    class Student:
    
        # Define the name and number when a student object is created, ex. student1 = Student('john', 025969102)
        def __init__(self, name, number):
            self.name = name
            self.number = number
            self.courses = {}
    
        # Display student name and number
        def displayStudent(self):
            print('Student Name: ' + self.name)
            print('Student Number: ' + self.number)
    
        # Add a new course and grade to students record
        def addGrade(self, course, grade):
            self.courses[course] = grade
    
        # Calculate the grade point average of all courses and display it
        def displayGPA(self):
            gpa = 0.0
            for course in self.courses.keys():
                gpa = gpa + self.courses[course]
            print('GPA of student ' + self.name + ' is ' + str(gpa / len(self.courses)))
  3. This is the Student class, with this class multiple Student objects can be created. There are a number of parts of this script that should look familiar, such as functions, for loops, variables. Functions indented underneath the class definition are called methods. Variables starting with self. are called public attributes. In the next steps lets break down this class and explain each part in detail.

PART 2 - Understanding Class Structure

  1. First is the definition of the class:
    class Student:
  2. This is how you give the class a name, now when you need to create a new Student object we know the class is called Student. Everything indented underneath the class Student: will be a part of the class.
  3. Next indented under the class is the __init__() method. This works similarly to a function, it contains code indented underneath it, that code is executed when you call the function. But __init__() is a special method, instead of manually calling this method, it will automatically be executed when we create a object. Inside the __init__() we create variables(object attributes), these are created using self.name, where name is the name of the attribute. The self. portion before the variable name is to let the class know that this variable can be accessed from anywhere inside the class and outside of the class, as a public attribute. Lets come back to this later.
    def __init__(self, name, number):
        self.name = name
        self.number = number
        self.courses = {}
  4. The next method definition prints out variables self.name and self.number, both of these variables were set in the __init__() method. Normally creating variables inside a function means they can only be accessed inside of that specific function. But classes give us the ability to share data throughout the class with all other objects. Place self. before the variable name to allow that variable to be shared with different functions, these variables are called public attributes. However, as we will soon come to see this variable is only shared within a single instance of the class(more on this to come).
    # Display student name and number
    def displayStudent(self):
        print('Student Name: ' + self.name)
        print('Student Number: ' + self.number)
  5. This next method accepts some arguments. The first argument of the method is self, this is required syntax for making methods inside of a class, and allows the method to access any variables you created/saved in the class previously, such as, self.courses. This method will take two additional arguments: course and grade. The method will then store these inside a dictionary self.courses, with the key being course and the value being grade.
    # Add a new course and grade to students record
    def addGrade(self, course, grade):
        self.courses[course] = grade
  6. This final method will do a bit of calculations. It will get the average of all values found inside the dictionary, add them up, and divide them by the number of values. When it finishes, the method will print out a message with the GPA of the student inside.
    # Calculate the grade point average of all courses and display it
    def displayGPA(self):
        gpa = 0.0
        for course in self.courses.keys():
            gpa = gpa + self.courses[course]
        print('GPA of student ' + self.name + ' is ' + str(gpa / len(self.courses)))
  7. Now that the class has been broken down, the code inside is simple on it's own, but what does it mean when it all works together? Before you can use a class, we must create a new object. A single class description can be used to create as many objects as you like, not just a single object. Our Student class will be used to create lots of different student objects, each object will be created using the blueprint of the class, but they will all be separate and contain separate data to store each and every student's data. Try to think of an object as any other python data structure (list, set, dictionary): you can create multiple dictionaries and store different data inside, even if some of the data is the same.
  8. In a new file, import the Student class:
    from student import Student
  9. Create a new student object and assign values to it:
    # Creates an instance of the Student class, it will be separate from all other objects created with the Student class:
    student1 = Student('John', '013454900')
  10. Have a look at the contents of the object student1:
    print(student1.name)
    print(student1.number)
    print(student1.courses)
    student1.displayStudent()
  11. Before going further with student1, lets create a second object, to demonstrate that these are different data structures:
    student2 = Student('Jessica', '023384103')
  12. Take a closer look at some of these different attributes and methods.
    print(student2.name)
    print(student2.number)
    print(student2.courses)
    student2.displayStudent()
  13. Now lets run some methods that are specific to each object's instance:
    # Add new courses for student1
    student1.addGrade('uli101', 4.0)
    student1.addGrade('ops235', 3.5)
    student1.addGrade('ops435', 3.0)
    
    # Add new courses for student2
    student2.addGrade('ipc144', 4.0)
    student2.addGrade('cpp244', 4.0)
  14. Investigate what has changed in each object:
    print(student1.name)
    print(student1.courses)
    print(student2.name)
    print(student2.courses)
  15. The method addGrade() changes the self.courses dictionary. But both student1 and student2 have their OWN courses dictionary.
  16. Once an object is created the attributes inside may be modified externally. Though you may need to be careful, if a value is a string, and you change it to another type such as a integer or a list, it's possible the class was not designed to deal with the different type and may throw a error when you run a method. For example, changing the name to a integer would break the displayStudent method, because it would try and concatenate strings and integers(maybe the method should be written better.
    # student1.name is a string like any other
    print(student1.name)
    student1.name = 'Jack'
    print(student1.name)
    len(student1.name)
  17. The final part to creating objects is understanding how to pass values into newly created objects, such as, student2 = Student('Jessica', '023384103'). How did it know that Jessica is the name instead of the long string of numbers? This is done when the class is written, inside the __init__() method. Look at the arguments used for in the __init__ definition:
    def __init__(self, name, number):
        self.name = name
        self.number = number
        self.courses = {}
  18. First was self, but this is required and we can ignore this for now. Next is name, this is the classes first argument when we instantiate(create) it, the second argument is number.
    # student3 is the object, Student is the class name, 'Jen' is the first argument passed to __init__, '034686901' is the second argument passed to init.
    student3 = Student('Jen', '034686901')

Create a Python Script Demonstrating Classes

  1. The following python script is broken. It has two major problems to fix and one new feature to add: first problem is providing the student number as an integer causes an error(TypeError) when displayStudent() is run, second problem is in displayGPA() may divide by zero(ZeroDivisionError) if no courses are added to the dictionary or the grades added to the dictionary are 0.0 floats. Finally, you will add a new method to this class that prints out a formatted list of all courses the student has taken.
  2. Create the ~/ops435/lab6/lab6a.py script.
  3. Use the following as a template(warning this is NOT the same as student.py):
    #!/usr/bin/env python3
    
    class Student:
    
        # Define the name and number when a student object is created, ex. student1 = Student('john', 025969102)
        def __init__(self, name, number):
            self.name = name
            self.number = number
            self.courses = {}
    
        # Return student name and number
        def displayStudent(self):
            return 'Student Name: ' + self.name + '\n' + 'Student Number: ' + self.number
    
        # Add a new course and grade to students record
        def addGrade(self, course, grade):
            self.courses[course] = grade
    
        # Calculate the grade point average of all courses and return a string
        def displayGPA(self):
            gpa = 0.0
            for course in self.courses.keys():
                gpa = gpa + self.courses[course]
            return 'GPA of student ' + self.name + ' is ' + str(gpa / len(self.courses))
    
        # Return a list of course that the student passed (not a 0.0 grade)
        def displayCourses(self):
            return
    
    if __name__ == '__main__':
        # Create first student object and add grades for each class
        student1 = Student('John', '013454900')
        student1.addGrade('uli101', 1.0)
        student1.addGrade('ops235', 2.0)
        student1.addGrade('ops435', 3.0)
    
        # Create second student object and add grades for each class
        student2 = Student('Jessica', '123456')
        student2.addGrade('ipc144', 4.0)
        student2.addGrade('cpp244', 3.5)
        student2.addGrade('cpp344', 0.0)
    
        # Display information for student1 object
        print(student1.displayStudent())
        print(student1.displayGPA())
        print(student1.displayCourses())
    
        # Display information for student2 object
        print(student2.displayStudent())
        print(student2.displayGPA())
        print(student2.displayCourses())
  • The displayStudent() method will not break if the object was created with an integer, example, student2 = Student('Jessica', 123456)
  • The displayGPA() will cleanly handle a ZeroDivisionError
  • The displayCourses() will return a list of courses that the student passed(not 0.0 grade)
  • The script should show the exact output as the samples(order of courses in list not important)
  • The script should contain no errors
Sample Run 1:
./lab6a.py
Student Name: John
Student Number: 013454900
GPA of student John is 2.0
['ops435', 'ops235', 'uli101']
Student Name: Jessica
Student Number: 123456
GPA of student Jessica is 2.5
['cpp244', 'ipc144']
Sample Run 2 (with import):
from lab6a import Student

student1 = Student('Jack', 931686102)

student1.addGrade('ops535', 2.0)

student1.addGrade('win310', 0.0)

student1.displayStudent()
# Will print: 'Student Name: Jack\nStudent Number: 931686102'

student1.displayGPA()
# Will print: 'GPA of student Jack is 1.0'

student1.displayCourses()
# Will print: ['ops535']

student2 = Student('Jen', 987654321)

student2.displayGPA()
# Will print: 'GPA of student Jen is 0.0'

student2.displayCourses()
# Will print: []
3. Download the checking script and check your work. Enter the following commands from the bash shell.
cd ~/ops435/lab6/
pwd #confirm that you are in the right directory
ls CheckLab6.py || wget https://raw.githubusercontent.com/Seneca-CDOT/ops435/master/LabCheckScripts/CheckLab6.py
python3 ./CheckLab6.py -f -v lab6a
4. Before proceeding, make certain that you identify all errors in lab6a.py. When the checking script tells you everything is OK - proceed to the next step.



LAB 6 SIGN-OFF (SHOW INSTRUCTOR)

Have Ready to Show Your Instructor:
Output of: ./CheckLab6.py -f -v
Output of: cat lab6a.py

LAB REVIEW

  1. What is object oriented programming?
  2. What is the difference between a object and a class?
  3. What does the dir() function tell you about objects?
  4. What happens if you try and make a copy of an object?
  5. When does the __init__() method get executed?
  6. What is an attribute? How do you create an attribute?
  7. What is a method?
  8. What is the difference between a method and a function?
  9. What is self used for in an object?
  10. What does it mean to instantiate an object?
  11. Import the Student class into ipython3, instantiate some objects, and try changing different attributes, and adding new attributes.
  12. Make a copy of lab6a.py called lab6practice.py, make the Student class accept another argument called program. When you create the new object: student = Student('name', '123456789', 'CTY'). Can you print the new students program out with student.program?
  13. Create a new method in lab6practice.py that checks to make sure the program is either "CTY" or "CNS", if it's not one of these, change the value to "unknown". Make sure the attribute is changed after your object is created.