Old version
This is the CS 111 site as it appeared on December 20, 2022.
Create a subfolder called lab10
within your
cs111
folder, and put all of the files for this lab in that
folder.
Begin by downloading
point.py,
saving it in your lab10
folder.
Open point.py
in Spyder. You’ll see that we’ve begun to define a
class called Point
that will serve as a blueprint for a new type
of object. Each Point
object represents a point with coordinates
(x,y)
in the Cartesian plane.
Locate the constructor function that we have provided for
Point
objects.
What is this function called? What does it do?
What are the names of the attributes that all Point
objects have?
How are those attributes defined?
Run point.py
in Spyder, and enter statements in the console to
create two Point
objects:
p1
, with coordinates (3, 4)p2
, with coordinates (-5, -12)Here is a template:
>>> p1 = # what should go here? >>> p2 = # what should go here?
Once you create your Point
objects, you should then be able to do
the following to see the values of their attributes:
>>> p1.x result: 3 >>> p1.y result: 4 >>> p2.x result: -5 >>> p2.y result: -12
By default, evaluating or printing an object will show you something that isn’t very helpful:
>>> p1 result: <__main__.Point object at 0x02DBED50> # you may get a different hexadecimal number after the word 'at'
To make it easier to display the current state of a Point
object,
copy the following method into your Point
class:
def __repr__(self): """ returns a string representation for the called Point object (self) """ s = '(' + str(self.x) + ', ' + str(self.y) + ')' return s
Make sure to put this method within the class definition, and indent it so that its header is aligned with the headers of the other methods that we’ve given you.
Once you have added this method, re-run point.py
in Spyder.
Like all __repr__
methods, this method returns a string
representation of an object. It will be called automatically
whenever a Point
object is printed, and whenever a Point
object
is evaluated from the console:
>>> p1 = Point(3, 4) >>> p2 = Point(-5, -12) >>> p1 # calls __repr__ on p1 result: (3, 4) >>> p2 # calls __repr__ on p2 result: (-5, -12) >>> print(p1) # also calls __repr__ on p1 result: (3, 4)
Examine the method called distance_from_origin()
in point.py
.
It computes the distance of the called Point
object (self
) from the
origin (0,0)
.
Given the Point
object p1
that we created above, which of the
following calls would allow us to determine its distance from the
origin?
distance_from_origin(p1)
p1.distance_from_origin(3, 4)
p1.distance_from_origin()
Point.distanceFromOrigin(3, 4)
Point.distanceFromOrigin()
Experiment with the calls in the console as needed until you find which of the calls above works. Make sure you understand how the call works, and how the method is able to access the information that it needs to compute the distance.
Examine the method called move_down()
in point.py
. What does it do?
Test it as follows:
>>> p1 = Point(3, 4) >>> p1 result: (3, 4) >>> p1.move_down(8) >>> p1 # what do you see?
Why doesn’t move_down()
need to return a value?
By default, using the ==
operator to compare two objects compares
the memory addresses of the objects. It doesn’t compare the internals
of the objects. For example:
>>> p1 = Point(3, 4) >>> p2 = Point(3, 4) # a different Point object with the same coordinates >>> p1 == p2 # what do you see? >>> p3 = p1 # copy the reference in p1 into p3 >>> p1 == p3 # what do you see?
Make sure that you understand the results that you obtain here. You may find it helpful to draw a memory diagram to assist your understanding.
Write a method called quadrant
that returns the number of the
quadrant (if any) in which the called Point
object (self
) falls.
The method should return:
For example:
>>> p1 = Point(3, 4) >>> p1.quadrant() result: 1 >>> p2 = Point(-3, 4) >>> p2.quadrant() result: 2 >>> p3 = Point(-3, -4) >>> p3.quadrant() result: 3 >>> p4 = Point(3, -4) >>> p4.quadrant() result: 4 >>> p5 = Point(0, -4) >>> p5.quadrant() result: 0
To allow the ==
operator to compare the internals of the objects,
add an __eq__
method. It should have the following header:
def __eq__(self, other):
and it should return True
if the called Point
object (self
) has
the same coordinates as the Point
object other
, and False
otherwise. For example:
>>> p1 = Point(3, 4) >>> p2 = Point(3, 4) # a different Point object with the same coordinates >>> p3 = Point(3, 5) >>> p1 == p2 result: True >>> p1 == p3 result: False
Write a method called flip
that negates and swaps the coordinates
of the called Point
object. For example:
>>> p1 = Point(3, -5) >>> p1.flip() >>> p1 result: (5, -3) >>> p2 = Point(2, 8) >>> p2.flip() >>> p2 result: (-8, -2)
As discussed in lecture, a dictionary is built-in data structure that allows us to store key-value pairs that connect two types of data.
For example, we might want to have a dictionary that keeps track of course enrollment numbers – i.e., that connects the name of a course to the number of students enrolled in that course:
>>> enrolled = {'cs111': 500, 'cs112': 400, 'cs131': 250}
In the console, enter the above assignment statement so that you can use this dictionary in the rest of this task.
What are the keys in this dictionary? What are the values?
Given a dictionary, you can use a key as if it were an index to look up the associated value. For example, what expression would allow us to lookup the enrollment of cs111?
>>> ___________________________ # what expression is needed? result: 500
We can add a new key-value pair k:v
to a dictionary d
by
using an assignment of the form d[k] = v
Write an assignment statement that updates our enrolled
dictionary to include the fact that the enrollment of cs132 is
220.
>>> ___________________________ # what statement is needed? >>> enrolled result: {'cs111': 500, 'cs112': 400, 'cs131': 250, 'cs132': 220}
More generally, if d
is a dictionary and k
is one of its keys,
we can use an expression of the form d[k]
in the same ways that
we would use a variable.
Write a statement that updates our enrolled
dictionary to
increase the enrollment of cs112 by 10 students. (Important:
You should not assign 410. You should increase the current
enrollment by 10 using a statement that would work for any
existing enrollment value.)
>>> ___________________________ # what statement is needed? >>> enrolled result: {'cs111': 500, 'cs112': 410, 'cs131': 250, 'cs132': 220}
As discussed in lecture, we can also use other built-in functions and operators with dictionaries. What do each of the following expressions produce?
len(enrolled)
'cs131' in enrolled
'cs210' in enrolled
'cs210' not in enrolled
500 in enrolled
In PS 8 (which will be posted after the midterm), you will use a dictionary to build a Markov model of a text file. Let’s look at another possible use of a dictionary when processing on a text file: keeping track of all of the words that begin with a given letter.
For example, if we process a text file containing the following text:
Dictionaries are handy and helpful!
the corresponding dictionary should look something like this:
{'d': ['dictionaries'], 'a': ['are', 'and'], 'h': ['handy', 'helpful!']}
Each key-value pair in the dictionary has:
a key that is a single lowercase letter
a value that is a list containing all words from the text that begin with that letter (with any uppercase letters converted to lowercase):
Here are the steps you should take:
Download the following files:
Make sure that you save both of them in your lab10
folder.
Open lab10task3.py
in Spyder, and you will see the beginnings of
a function called build_dict
that takes the name of a text file as
its only input. It should create and return a dictionary of the
form described above that is based on the contents of the text file.
Review the provided code. What does it do?
Complete the body of the provided for
loop so that it makes the
appropriate changes to the dictionary d
for the current word
w
.
Notes:
The necessary steps will depend on whether the appropriate key
for w
is already in the dictionary, so you will
need an if-else
statement like the one that we used in lecture
when updating a dictionary.
Don’t forget that the values in this dictionary are lists, so your code will need to reflect that.
Use concrete cases to help you. For example, if w
is the word
'committed'
, what line of code would you need if the corresponding
key is not already in d
? If the corresponding key is
already in d
?
After you have made the necessary changes, run lab10task3.py
in
Spyder and test your function using the edited_mission.txt
file that
you should have downloaded above. (This text file contains an edited version of BU’s mission statement.)
>>> d = build_dict('edited_mission.txt') >>> d['a'] result: ['a', 'and', 'an', 'amazing!'] >>> d['c'] result: ['comprehensive', 'committed', 'committed']
Last updated on January 6, 2023.