(fill in your two names here)
Facilitator: (fill in name)
Spokesperson: (fill in name)
Process Analyst: (fill in name)
Quality Control: (fill in name)
If there are only three people in your group, have one person serve as both spokesperson and process analyst for the rest of this activity.
At the end of this Lesson, you will be asked to record how long each Model required for your team. The Facilitator should keep track of time for your team.
As programs get longer, it becomes easier to design, write, test and debug the program if the program is ordered into separate stand-alone parts. Object oriented programming is a programming model that organizes a large program into smaller parts (classes) by the objects (e.g., the nouns) involved.
For example, if you were simulating a biome, you might separate the program into a predator class, a herbavore class, and a plant class.
0. As a group, choose one scientific application of object oriented programming and identify at least three classes that might be used for that application.
Classes and objects are the two main aspects of object oriented programming. A class creates a new type where objects are instances of the class. Objects can store data that belong to the object, which are called instance variables. Objects can also have functionality by calling functions that belong to a class, which are called methods of the class.
Run the code in the cell below to define the Atom
class:
In [ ]:
class Atom:
"""A simple Atom class"""
avogadros = 6.02E23 # floating point number representing Avogadro's Number
def set_atomic_mass(self,grams_per_mole):
self.atomic_mass = grams_per_mole
def get_atomic_mass(self):
print("the mass is " + str(self.atomic_mass))
return self.atomic_mass
Type each of the following lines of code in separate Jupyter code cells (it won't work correctly if you type them in a single Jupyter cell):
oxygen = Atom()
oxygen.set_atomic_mass(16)
print(oxygen.get_atomic_mass())
carbon = Atom()
carbon.set_atomic_mass(12)
print(carbon.get_atomic_mass())
print(oxygen.get_atomic_mass())
1. Examine the code in the class:
1a. What is the name of the class defined in Model 1?
1b. Identify the names of the two methods defined in Model 1.
1c. Examine the first parameter used for every method in the class. What is the variable name for this first parameter, for all methods in a class?
1d. How does the number of parameters in the method definition differ from the number of arguments given when the method is called?
2. Now examine the code that you typed into separate Jupyter code cells.
2a. How many different objects were created in Model 1?
2b. Identify the variable name of each object.
3. Consider the instance variable self.atomic_mass
created in the method set_atomic_mass
.
3a. What is the type of this instance variable (boolean, integer, floating point number, string, etc)? Add a comment to the set_atomic_mass
method definition noting the type as well.
3b. Identify the value of this variable for each object created in Model 1.
3c. Explain how you know from Model 1 that the instance variable self.atomic_mass
has a value that can be used outside the method where it is assigned a value (i.e., it is not a local variable).
3d. In order for these two objects to have different values for the same instance variable, what might a possible value of the self
parameter be, when the get_atomic_mass method
is called for each case?
4a. Write Python code to a new Atom
object called hydrogen
.
In [ ]:
4b. Call the get_atomic_mass
method on hydrogen
.
In [ ]:
4c. Describe the reason for the error you get if you call get_atomic_mass
without first calling set_atomic_mass
on the hydrogen
object.
For each class defined, you can provide a constructor that initializes instance variables of a new object. In Python, the constructor is always called __init__
(with two underscores before and after init, four underscores total). The constructor is called when you create a new object (e.g., carbon = Atom()
).
Copy the Atom definition into the code cell below. Add the following constructor to your Atom class. By convention, it should be the FIRST method inside your class (don't forget to indent).
def __init__(self, grams_per_mole):
self.atomic_mass = grams_per_mole
make sure to run this new version of Atom
In [ ]:
Type each of the following lines of code in separate Jupyter code cells (it won't work correctly if you type them in a single Jupyter cell):
carbon = Atom(12)
print(carbon.get_atomic_mass())
print(self.atomic_mass)
It is possible to make a parameter optional by adding a default value for that parameter using an =
operator, as in:
def __init__(self, grams_per_mole=12):
self.atomic_mass = grams_per_mole
The Atom
objects can now be created in two ways.
Type each of the following lines of code in separate Jupyter code cells (it won't work correctly if you type them in a single Jupyter cell):
element = Atom(16)
print(element.get_atomic_mass())
carbon = Atom()
print(carbon.get_atomic_mass())
carbon.set_atomic_mass(13)
print(carbon.get_atomic_mass())
5. What is (always) the name of the constructor in a class?
6. Explain how you know from Model 2 that the constructor is called when an object is created.
7. Consider your answer to question 4 from the previous Model. What is one advantage of defining a constructor for a class?
8. Explain how you know from Model 2 that the instance variable self.atomic_mass
is not a global variable?
9. Recall previously that we learned that variables have local scope (variables defined within a function) or global scope (variables created in the non-indented part of a Python script). What would you define as the scope of the variable initialized in the constructor?
10. Why might you still define a set method (e.g., set_atomic_mass
) if a constructor method has been defined for the class?
Copy the Atom definition in the code cell below. Add the following three methods to the end of your Atom class:
def calculate_mass_from_moles(self, moles):
""" calculate the number of grams from the number of moles of the element """
mass = self.atomic_mass*moles
return mass
def calculate_mass_from_atoms(self, atoms):
""" calculate the number of grams from the number of atoms of the element """
moles = atoms / Atom.avogadros
answer = self.calculate_mass_from_moles(moles)
return answer
def calculate_atoms_from_mass(self, grams):
""" calculate the number of atoms from mass in grams """
atoms = grams / self.atomic_mass * Atom.avogadros
return atoms
make sure to run this new version of Atom
In [ ]:
Type each of the following lines of code in separate Jupyter code cells (it won't work correctly if you type them in a single Jupyter cell):
hydrogen = Atom(1)
number = hydrogen.calculate_atoms_from_mass(2)
print(number)
print(hydrogen.calculate_mass_from_atoms(number)
11. Examine the calculate_mass
method.
11a. Identify at least three variables in the calculate_mass
method.
11b. For each variable, give the scope (local, class, global) of the variable.
12. What determines whether a variable in a method is defined as an instance variable or simply a local variable?
13. Examine the calculate_atoms_from_mass
method.
13a. Identify the variable used in the calculate_atoms_from_mass
method, that was initialized inside the Atom class but outside the constructor and methods?
13b. Explain the syntax for referring to this class variable (and how it differs from an instance variable).
14. The calculate_atoms_from_mass
calculates the number of atoms that are in a specific number of grams of the element.
14a. Give the equation for the inverse calculation (the mass, in grams, of a given number of atoms) by inversing the equation from calculate_atoms_from_mass
. Your equation should not look like the code in calculate_mass_from_atoms
.
14b. Explain how the calculate_mass_from_atoms
method differs from your answer (a) to calculate the mass.
14c. Take one minute and list any advantages you perceive for writing calculate_mass_from_atoms
as it was defined in the Model.
15. Would it be possible to write the calculate_atoms_from_mass
method in the Atom class as a stand alone function? If so, explain how the function would differ.
16. The string
class is another class you have programmed with this semester.
16a. What is the data in a string object?
16b. Give one example of a string method.
17. Take one minute and list any advantages you perceive for writing code as methods in classes in comparison to stand alone functions.
18. Add a new instance variable to the existing Atom class' constructor. The instance variable, atomic_number
, will represent atomic number. Carbon’s atomic number is 6.
19. Next add a get_atomic_number
method to the Atom class that returns the atom’s atomic number. Test your method before proceeding to the next step.
20. Add a set_atomic_number
method that allows the atom’s atomic number to be set to any positive number. Negative and zero numbers should be ignored (have no effect).
21. Modify the constructor in the Atom class so it also assigns a default value to atomic_number
. Be sure to run and test this new version of the Atom. You should be able to create a two Atoms (one default, and another new Atom with a different atomic_mass and atomic_number) with this constructor. All the new methods and previous methods should work.
Webinar on Object Oriented Programming in Python (requires free academic subscription):
How much time did it require for your team to complete each Model?
Model 1:
Model 2:
Model 3: