- Due before 23:59 Wednesday, August 31
- Submit using the submit program
301 lab 01.
Object-Oriented Programming is a really big part of implementing data structures, so it's important that we practice before our first Project.
This class will be trivial in functionality, but will serve as an example
for class structure. In a file called
lab1.py, make a class called
Adding. This class should have:
- A constructor (sometimes called an initializer in Python), which takes two arguments (they'll be integers), and stores them as fields in the class.
- A function called
add_third, which takes an additional integer, and adds the three numbers together, before returning them (not printing them).
Copy-paste the following code into a file called
the same directory as
should run your class correctly, and print the number 18:
1 2 3 4 5 6
from lab1 import Adding if __name__ == "__main__": obj = Adding(5, 3) added = obj.add_third(10) print(added)
Suppose we create a class called
AClass, and make an object of
that type, like so:
obj = AClass(). We then call
print(obj). What will print?
A right answer here is "I have no idea." The reason you have no idea is because you don't even know what data is stored within this object, so how can you possibly know what the right way to print it to the screen is? Python is in the same bind; this is your class, how can it know what you want to display?
Fortunately, there's a way of telling Python how to print things: the
__str__ function (special functions in Python usually start and
end with double-underscores, to avoid accidental name collisions). Whenever
an object needs to be printed, or otherwise converted to a string, Python goes
looking for that object's
__str__ function; if it exists, it runs
that function, and that function returns a string (it does not print the
string, it just returns it); the returned string is then printed, or
used as the string representation.
__str__ method to your
Adding class, so that when
an object of that type is printed, you get output that looks like this:
Adding: (firstnum, secondnum)
The following testing code:
1 2 3 4 5
from lab1 import Adding if __name__ == "__main__": obj = Adding(3,9) print(obj) #Calls __str__ and prints what is returned
should result in the following output:
$ python3 lab1_test2.py Adding: (3, 9)
Similarly, the following testing code:
1 2 3 4 5 6 7
from lab1 import Adding if __name__ == "__main__": obj = Adding(3,9) strVersion = str(obj) #Calls __str__, and stores what is returned print('here') print(strVersion)
Should result in the following output (notice how the object is printed AFTER 'here' due to the fact that __str__ returns, not prints, the string):
$ python3 lab1_test3.py here Adding: (3, 9)
We're going to make a little program to keep track of which processes are running on a network and what their memory requirements are. Here's a description of the objects involved. A Process is an object which contains a name, and an int which indicates the number of KB of memory required to run that Process. A Machine is an object with a name, a list of Processes running on that Machine, and an int indicating the maximum amount of available memory in KB. A Network contains a list of Machines.
Place all three of these classes in a single file named
network.py. You can download a testing file here, which can help you test after finishing
each class. I won't usually give you a testing file like this, and will
require you to make your own, to have full confidence in what you're turning
in. Take note of how I wrote it!
Process has two fields,
name (a String) and
memoryReq (an int). As far as methods, it should have:
- a constructor (sometimes called an initializer), which takes both a String and an int, in that order, and
__str__, which returns a string of the form
processName: memoryReqKB(for example, "aName: 5KB")
Machine has three fields,
name (a String),
processList (a list of Processes running on that machine), and
totalMem (an int). For methods, it should have:
- a constructor, which takes a name and totalMem as arguments, and sets
processListto be an empty list,
addProcess, which takes a Process as an argument, and appends it to
availableMemory, which takes no arguments (aside from
self), and returns the result of subtracting the total amount of memory required by the Processes in
__str__, which returns a string describing the machine of the form
machineName, totalMemKB aProcessName: someKB anotherProcessName: someOtherKB
Network has as a field a list of Machines named
For methods, it should have:
- a constructor, which takes no arguments (again, aside from
self), and sets
machinesto be an empty list;
addMachine, which takes a Machine as an argument, and appends it to the list
addProcess, which takes a Process as an argument, figures out which Machine in
machineshas the most available memory (by calling their
availableMemorymethod), and assigns the Process to that Machine (using its
__str__, which returns a string describing the entire network, of the form
Network: machineName, totalMemKB aProcessName: someKB anotherProcessName: someOtherKB anotherMachineName, totalMemKB aProcessName: someKB anotherProcessName: someOtherKB
(Note the rest of this lab is an optional exercise for your enrichment, to challenge you and learn something and earn the admiration of your professor and peers. It might be tangibly useful if e.g. you are going to ask me to write you a recommendation letter at some point in the future, but mostly it'll just make you a better programmer!)
There's one thing that can go wrong in the "Network" above, even if all of the arguments have the right types and would otherwise make sense: The network might not have any machine with enough memory for the process that you want to add!
This is a good example of where it would make sense to throw
a Python exception. So for this part, I want you to add an exception class
OutOfMemory, and make it so this exception is
thrown whenever the
addProcess method of
finds that there isn't enough memory in any machine to handle the situation.
It would probably be a good idea to make the same thing happen for the
addProcess method in
Machine as well.
I'm not going to tell you exactly how to do this. Use Google, ask questions,
and think about the simplest and most straightforward way to do this
in Python. You'll definitely have to make a new
your exception and put a
throw command somewhere.
Still want more to do? OK then!
Add one more method to the
Network class called
multiProcess, which takes a list of processes as its
single argument, and adds all of them to various machines in the network.
One way to do this (and a good way to start) would be to add them one
at a time, using the
addProcess method you already wrote.
But this might not always lead to the very best way of using the memory
resources evenly. Can you think of anything better? Try it!