As we have seen in class, one very useful property of object-oriented programming in Python is the user's ability to create objects and their respective methods which correspond to real-world concepts. This allows for the real-world application of computer programming.
During the first lab, we were assigned to create a new Python class in order to store words and their respective frequencies in a text file, along with class methods for finding the "top n words" and for comparing two different instances of the class. As we started the lab, the first challenge that stroke my partner and I was how we would transform the text file into a list of its words, since the words in the file were separated by spaces and followed by various types of different non-alphabetical characters. We finally decided to use the string method split to achieve our results; however, we were still unable to rid the words of all punctuation marks, since we were unable to figure out a way to delete all of them at once.
The most challenging and frustrating part of the lab, which took us almost the entire 2 hours was the method find_top_n, since it required for the different frequencies to refer to all words with that specific frequency, as well as for these words to be in alphabetical order. The way we decided to solve this problem was by creating a dictionary of frequency to a list of words in alphabetical order and then transform this dictionary into a list of words from most frequent to less frequent in alphabetical order. This took an extreme amount of effort, and, in spite of it working properly, the code seemed to be particularly long and confusing; however, we were unable to find a way to simplify it any further.
The second lab, which was done this week, was particularly straightforward in my opinion. It simply used the main ideas brainstormed in class to create the class Stack in order to create a similar class named Queue. The only problem we ran into was that Queue's method dequeue had a linear running time in comparison to Stack's pop's constant time, making it less efficient when dealing with extremely long lists. The way we decided to go about this problem was by modifying this method so that the similar method front pointed to the next item in the list each time dequeue was performed; however, in this case, dequeue was unable to remove the first item in Queue._items.
Two very interesting and useful concepts that we learned this week were that of inheritance and exceptions. Class inheritance allows for the creation of a new class which inherits all methods and attributes of the original class. This allows for the reuse of existent code, saving the time and trouble of having to rewrite particularly similar code. This technique also allows for specific methods, including __init__, to be modified in this new class so that it behaves slightly differently from the original class.
Exceptions are created whenever a runtime error occurs; they can be handled using try statements in order to prevent a certain program from crashing, and they can also be created and raised in writing code in order to let the user know what problem he ran into.
