1st PROGRAMMING ASSIGNMENT – Part 1A
Virtual Dice Throwing
This is an introductory programming exercise in order to refresh your last year’s knowledge of programming and get you introduced to Python. The program to write should emulate virtual dice throwing. It should get from the keyboard the number of sides of the virtual dice and the number of times to be thrown, the latter should be a multiple of the number of sides. The program should then throw the dice and print out the number of times each side occurred. Given that random numbers will be used, you should be able to see that the higher the number of throws, the closer the results will be towards approximately equal occurrence of all sides (same probability). The program should deal gracefully with incorrect type of arguments through checks and exceptions.
This program can be in fact an extension of the coin thrower program which can be found on the Week 2 Random Number Generation lecture material. You should work on this assignment in the first lab session of the week commencing 16 January.
1st PROGRAMMING ASSIGNMENT – Part 1B
Calculating the Mean and Variance of a Data Set – “the Long Way”
This is another introductory programming exercise so that you start getting familiar with some more sophisticated aspects of Python. “The long way” is mentioned above because the description of this assignment also serves as a tutorial introduction to various aspects of structured and object-oriented programming in Python, and for this reason this description is 5 pages long. It also includes a good part of the assignment already implemented in order to show how things should be done properly. So please go through this description very carefully as it constitutes effectively an additional complementary lecture.
The program to be developed in this exercise should calculate the mean and variance of a set of numbers, i.e. “the data set”. This is something that could be easily done in C through a program that would have the following structure: two C functions mean and variance and a main program that initialises an array of numbers, invokes the two functions by passing to them the array as parameter and prints the respective results. The “signature” of the two functions would be the following:
float mean (int ndata, float data[]) float variance (int ndata, float data[])
Note that in C we need to pass the size of the array, i.e. ndata, as a separate arameter, as the array is effectively only a pointer to its first element, no more than that.
We will also write the mean and variance functions, which in Python will have the following simpler signature: def mean (data) def variance (data)
Finally, we will write a main program which will allow the initialisation of the data set in a number of ways and will then compute the mean and standard deviation. We are now ready to implement our first simple object-oriented class and program in Python in an incremental manner, showing basic parts of it and its overall layout but omitting the complete implementation, which you should do.
import random
# for Random class methods in the full version
class NumberList:
def __init__ (self):
self.__data = []
# the class constructor
# initialises the __data “private” instance variable to an empty list
def getData (self):
return self.__data;
def setData (self, data):
self.__data = data
# end class
# returns the contained data list to users of the class
# initialises the list with “externally-created” data
def mean (data):
# function implementation goes here, you should do this
def variance (data):
# function implementation goes here, you should do this
def main ():
mydata = [0.1, 1.1, 2.1, 3.1, 4.1]
nlist = NumberList()
nlist.setData(mydata)
# hardcoded data set values, list with 5 elements
# create new empty NumberList object instance
# fill it in with the data set
print("Numbers: " + str(nlist.getData()))
# print the data set
print("Mean: " + str(mean(nlist.getData())))
# calculate and print mean
print("Variance: " + str(variance(nlist.getData()))) # calculate and print variance
if __name__ == "__main__":
main()
Note: in the main function above we could have passed directly mydata to the mean & variance functions. But we did it in an object-oriented manner by creating a NumberList object instance which contains mydata and then retrieved the contained data using the getData() method in order to to pass it to the mathematical functions. In a more complex program, such a data set object could have been created and filled in elsewhere and passed as parameter to a function in order to calculate the data set mean & variance, so we used this more general approach.
We have now implemented our first Python program which calculates the mean and variance of a data set with “hard-coded” values, with the data set implemented in an object-oriented manner through the NumberList class. It would be nice to extend this class to be able to get the data set size and values in various ways: by a human user from the keyboard, by randomly producing the values within a particular range, or by reading a file which contains the data values, one per line.
Considering the data-from-keyboard approach, we introduce the getNDataFromKeyboard() method which will read the number of data elements expected from the keyboard. It will also need to check that the number specified by the user is >= 2 as otherwise there is no point in running the program. This method should be private, given that it will be only called by another class method getDataSetFromKeyboard() which we will subsequently introduce. Hence we name the former __ getNDataFromKeyboard() according to the Python convention for naming private class members. We include the complete method implementation overleaf.
# additional NumberList class methods
def __getNDataFromKeyboard (self): # “private” method names in Python start with __
print("Enter the number of data set elements: ")
ndata = 0
gotNDataCorrectly = False
# a flag to loop until we get ndata correctly
while gotNDataCorrectly == False:
try:
ndata = float(input())
# read from the keyboard, accept also strings & convert
if ndata % 1 == 0 and ndata >= 2: # check for integer input >= 2
gotNDataCorrectly = True
else:
print("__getNDataFromKeyboard: ndata should be >=2")
except (ValueError, SyntaxError):
print("__getNDataFromKeyboard: ndata should be an integer!")
# end while loop
return int(ndata) # return ndata as int
def getDataFromKeyboard (self):
ndata = self.__getNDataFromKeyboard()
# here you should write code that gets exactly ndata numbers from the keyboard
# and adds them to the __data instance variable using the list append method;
# you will need a while loop in similar fashion to __getNDataFromKeyboard
Note that the getNDataFromKeyboard method does not use the data instance variable. It could be made in fact a static class method, static methods are those that do not have access to the class instance variables and, in fact, can be called without creating an object instance by simply preceding them with the class name, e.g. NumberList.__getNDataFromKeyboard(). In order to make this method static, we need to use the @staticmethod decorator and in this case the method would not take the self parameter while everything else would stay the same. Although it does not make any difference when running the program, it is better programming practice and you should do it that way.
@staticmethod
# this decorator tells the interpreter that the following method is static
def __getNDataFromKeyboard (): # note the absence of self, static methods do not have it
# normal method implementation follows
Finally, we can also add a final method to our NumberList class to initialise the data set by reading values from a file. By doing this, you will learn some elementary file manipulation, although more elaborate file handling will be taught in the second part of the term. You should use the open function to open the file in read mode and then in a for loop you should go through every line of the file, using the strip method of every text line by doing strip(‘\n’) to remove any spaces and the newline character and convert the resulting value to float, making sure that you catch exceptions if the value cannot be converted. The signature of the method will be:
def getDataFromFile (self, fileName):
# method implementation follows
So we implemented the two different main programs above in only a few lines of code by using the class NumberList which we can reuse anywhere. A key aspect of object-oriented programming is to design and implement highly reusable classes and this exercise demonstrated the benefit of doing this.
But in order to also demonstrate some other aspects of Python and programming languages in general, we will create a more sophisticated version of the main program. This will combine the three options we used above; it will also allow the user to pass the size and low/high of the random data set from the command line. So when the program is invoked with no arguments at all it will get the values from the keyboard; when it is invoked with one argument this should be the name of a file and it will read the data from a file; and when it is invoked with two or three arguments, it should produce the data set values randomly.
Also as NumberList is a reusable class, we will leave it in file NumberList.py which we have used until now and we will put the more sophisticated main program described above in file MeanAndVariance.py - see implementation below.
from NumberList import NumberList # NumberList class is in file NumberList.py
import sys
# for sys.argv and sys.exit()
def main ():
nlist = NumberList()
# create an empty NumberList instance
nargs = len(sys.argv) # argv contains the program name and arguments, as in C
if nargs == 1:
# no arguments, actually only the program name hence value 1
nlist.getDataFromKeyboard()
elif nargs == 2:
# filename argument, get data from file
nlist.getDataFromFile(sys.argv[1])
elif nargs == 3 or nargs == 4: # produce data set randomly
if nargs == 3:
nlist.getRandomData(sys.argv[1], sys.argv[2])
else: # nargs = 4
nlist.getRandomData(sys.argv[1], sys.argv[2], sys.argv[3])
else:
print(“incorrect number of arguments, try again”);
sys.exit()
# terminate program
print("Numbers: " + str(nlist.getData()))
print("Mean: " + str(mean(nlist.getData())))
print("Variance: " + str(variance(nlist.getData())))
By studying carefully the description of this assignment and by implementing this program you will get familiar with a number of Python features and get introduced to object-oriented programming. As already stated in the beginning, the detailed description of this assignment serves as an introductory tutorial to object-oriented programming. Another aspect of this assignment is that it introduces “incremental development”: you first implement a simple program that works with a fixed size / hard-coded values data set, then extend it to work with a data set that the user provides from the keyboard, then extend it to also work by producing the data set randomly with a user-specified size and range; then extend it to also work by reading the data set values from a file; and finally enhance the main function to enable running the program with all these options.
1st PROGRAMMING ASSIGNMENT – Part 1C
Shape Inheritance
This exercise has the purpose first to get you to implement the Shape, Point, Circle and Cylinder classes as in the lecture notes in order to get to understand better, assimilate and actually code the inheritance features taught in the lectures. Although you can simply copy the code from the notes, it would be certainly more beneficial to write the code yourselves by looking at the notes in order to realise how object-oriented features related to inheritance are exercised and understand / assimilate the relevant principles. In addition to the classes in the notes, you should also design and implement the following shape classes exploiting inheritance: Sphere, Rectangle, Square and Cube.
Having implemented these classes, you should write a which gets input from the user/keyboard to create an instance of any one of these. The user should be able to create as many of these shapes and s/he wants. The menu should also allow the user to print out the created objects, either selecting a particular one or printing all of them. The user should also be allowed to remove/delete an existing shape from the list. Finally, the user should be allowed to modify a particular shape. The program should print the objects it keeps by using only the Shape getName(), toString(), getArea() and getVolume() methods, i.e. treating all these objects “polymorphically” as “shapes”. Note that modifying a shape cannot be done polymorphically, specific functions will be required to modify each type of shape. The program should deal gracefully with incorrect type of arguments through checks and exceptions.