Quiz 03 Practice


Questions

Solutions for each problem can be found at the bottom of this page.

Conceptual Questions

  1. A class definition provides a pattern for creating objects, but doesn’t make any objects itself. (T/F)
  2. By convention, Python class names start with a lowercase letter. (T/F)
  3. When you define a method in a class, all objects of that class have that method associated with it. (T/F)
  4. The first parameter of a method is a copy of the object the method is called on. (T/F)
  5. A class definition must come before an object of that class is instantiated. (T/F)
  6. You must have an instance of a class (an object) to call the class’s constructor. (T/F)
  7. Constructors must have the self parameter in their signature. (T/F)
  8. Constructors must take at least one parameter other than the self parameter. (T/F)
  9. Objects are passed into functions by reference. (T/F)
  10. The type of an object is the same as the name of the class it is an instance of. (T/F)

Memory Diagrams

  1. Produce a memory diagram for the following code snippet, being sure to include its stack and output.
    class Point:
        """Models the idea of a point at location (x, y)."""
        x: int
        y: int

        def __init__(self, x: int, y: int):
            """Constructor definition!"""
            self.x = x
            self.y = y


    class Path: 
        """Models the idea of a path from point a to point b."""
        a: Point
        b: Point

        def __init__(self, a: Point, b: Point):
            """Constructor definition!"""
            self.a = a
            self.b = b
        
        def scale(self, amount: int) -> None:
            """Scales the points by a specified amount."""
            self.a.x *= amount
            self.b.y *= amount

        def translate(self) -> None:
            """Moves the points up 2 units and right 5 units."""
            self.a.x += 5
            self.a.y += 2
            self.b.x += 5
            self.b.y += 2


    def main() -> None:
        """Entrypoint of the program."""
        p1: Point = Point(2, 1)
        p2: Point = Point(3, 6)

        line1: Path = Path(p1, p2)
        line2: Path = line1

        line2.translate()
        line2.scale(2)

        print(f"{line1.a.x} , {line1.a.y}")
        print(f"{line2.a.x} , {line2.a.y}")


    if __name__ == "__main__":
        main()
  1. Produce a memory diagram for the following code snippet, being sure to include its stack and output.
    """Diagramming practice for Quiz 03."""

    from __future__ import annotations


    class Phone:
        """Represents a phone as a class."""

        number: str
        name: str
        contacts: list[Phone]

        def __init__(self, number: str, name: str):
            """Creates a phone object."""
            self.number = number
            self.name = name
            self.contacts = []

        def add_contact(self, other: Phone) -> None:
            """Making friends!"""
            if not (other in self.contacts):
                self.contacts.append(other)
        
        def add_contacts_friends(self, other: Phone) -> None:
            """A friend introduces you to a new friend group :D."""
            if other in self.contacts:
                print("Now that's quite a circle you're building!")
                for contact in other.contacts:
                    if not (contact in self.contacts):
                        self.contacts.append(contact)
            else:
                print(f"Gotta find a way into the group somehow, {self.name}.")


    def main():
        """Entrypoint into the program."""
        main_character: Phone = Phone("919-999-9999", "Johnny")
        new_friend: Phone = Phone("704-999-9999", "Bianca")
        tv_ad: Phone = Phone("877CASHNOW", "Wentworth")
        new_friend.add_contact(tv_ad)

        main_character.add_contacts_friends(new_friend)

        main_character.add_contact(new_friend)
        main_character.add_contacts_friends(new_friend)


    if __name__ == "__main__":
        main()
  1. Produce a memory diagram for the following code snippet, being sure to include its stack and output.
    """From number grades to letters."""


    def main() -> None:
        """The entrypoint of the program."""
        student_grades: dict[str, int] = {"Andre": 92, "Jonny": 79, "Ania": 86, "Wendy": 55}
        curve(student_grades)
        letter_grades: dict[str, str] = grading_scale(student_grades)
        print(letter_grades)


    def curve(number_grades: dict[str, int]) -> None:
        """Curves number grades."""
        max: int = 0
        for student in number_grades:
            if number_grades[student] > max:
                max = number_grades[student]
        
        curve_amount: int = 100 - max
        for student in number_grades:
            number_grades[student] += curve_amount


    def grading_scale(number_grades: dict[str, int]) -> dict[str, str]:
        """Converts grades formatted as numbered into letter grades."""
        gradebook: dict[str, str] = {}

        for student in number_grades:
            
            if number_grades[student] >= 90:
                gradebook[student] = "A"

            elif number_grades[student] >= 80:
                gradebook[student] = "B"

            elif number_grades[student] >= 70:
                gradebook[student] = "C"

            elif number_grades[student] >= 60:
                gradebook[student] = "D"

            else: 
                gradebook[student] = "F"
        
        return gradebook


    if __name__ == "__main__":
        main()

Please check the practice memory diagram page for more practice!

Class Writing

  1. This class is slightly challenging, but take it step by step! Create a ChristmasTreeFarm class with the following specifications:
    1. The ChristmasTreeFarm class should have one attribute: a list[int] named plots.
      • Basic behavior of plots (you will define this later):
        • This list will hold values that represent the size of the tree planted in each plot.
        • If the value at an index of the list is 0, then the plot at that index is empty (does not have a tree).
        • Any value other than 0 indicates that a tree is growing in that plot!
    2. The constructor for the class should take two arguments: plots: int and initial_planting: int, both of type int.
      • The first parameter, plots, represents the total number of plots in the farm. (Notice that the attribute plots and the parameter plots for this constructor are different, and represent different things!)
      • The second parameter, initial_planting, represents the number of plots that that will have trees already planted in them. These initially planted plots will be trees of size 1.
      • The constructor should initialize the plots attribute to an empty list, and then append initial_planting trees of size 1. After that, the constructor should fill the rest of the plots with zeroes to indicate that they are empty!
    3. The class should define a method called plant.
      • This method should have a parameter of type int, representing the plot index at which a tree should be planted.
      • The tree should be size 1 when planted. If this method is called on a plot that already has a tree, the old tree will be uprooted and replaced with a new baby tree (size 1).
    4. The class should define a method called growth.
      • This method should increase the size of each planted tree by 1. (Remember that unplanted plots are represented by a 0 in the plots list.)
    5. The class should define a method called harvest.
      • This method should have a parameter replant of type bool that will determine whether this method replants trees (sets them to size 1 after harvest) or leaves the plots empty (sets them to size 0 after harvest).
      • For this method, trees that are at least size 5 will be harvested. The method will return the count of how many trees were successfully harvested (type int).
    6. The class should overload the addition operator.
      • This method should work between two objects of type ChristmasTreeFarm.
      • The method should return a new ChristmasTreeFarm object whose size is the sum of the given ChristmasTreeFarm’s, and whose initial plantings are the sum of the number of planted trees in the given ChristmasTreeFarms.
    7. Check your code: If you want to check and see if your code works, you can use the autograder. Check out the instructions below to join the autograder Gradescope if you haven’t yet. (It’s the same one used for QZ02 practice!) For the autograder to work, you need to save your file in your lessons folder, in a folder called “practice” and in a file called “tree_farm.py”. Create the zip folder by running the command: python -m tools.submission lessons/practice

Function Writing

  1. Write a function called find_courses. Given the following Course class definition, find_courses should take in a list[Courses] and a str prerequisite to search for. The function should return a list of the names of each Course whose level is 400+ and whose prerequisites list contains the given string.
    class Course:
        """Models the idea of a UNC course."""
        name: str
        level: int
        prerequisites: list[str]
  1. Write a method called is_valid_course for the Course class. The method should take in a str prerequisite and return a bool that represents whether the course’s level is 400+ and if its prerequisites list contains the given string.

  2. Check your code: If you want to check and see if your code works, you can use the autograder. Check out the instructions below to join the autograder Gradescope if you haven’t yet. (It’s the same one used for QZ02 practice!) For the autograder to work, you need to save your file in your lessons folder, in a folder called “practice” and in a file called “courses.py”. Create the zip folder by running the command: `python -m tools.submission lessons/practice

Autograder Instructions

Join the Gradescope class for practice problems with the code: 4V7PB5 (Do this by going to your Gradescope homepage and clicking on “Enroll in Course”) Do not compress these files before submitting. Simply submit the .py files.

Solutions

Conceptual Questions

  1. True
  2. False
  3. True
  4. False
  5. True
  6. False
  7. True
  8. False
  9. True
  10. True

Memory Diagrams

The memory diagram has two columns titled Stack and Heap and a column below titled Output. 
The Stack includes 7 frames in the following order from top to bottom - Globals, main, Point # _ _ init _ _, Point # _ _ init _ _, Point # _ _ init _ _, Path # _ _ init _ _, Path # translate, and Path # scale.
The Globals frame has 4 variables including Point, Path, and main, and _ _ name _ _. 
Point points to a Class on the heap from lines 1 to 9.
Path points to a Class on the heap from lines 12 to 32.
main points to a function on the heap from lines 35 to 47.
_ _ name _ _ is assigned the string "_ _ main _ _".
The main frame has 5 items including the return address.
The RA is 51.
The variable p1 points to a Point object on the heap. The point object has two attributes, x and y. x has previous values of 2 and 7, and a final value of 14. y has an initial value of 1 and a final value of 3.
The variable p2 points to a separate Point object on the heap. The Point object has two attributes, x and y. x has an initial value of 3 and a final value of 8. y has previous values of 6 and 8, and a final value of 16.
The variable line 1 points to a path on the heap with attributes a and b. a points to the same point object on the heap that p1 points to. b points to the same point object on the heap that p2 points to.
The variable line 2 points to the same path object on the heap that the variable line 1 points to.
The Point # _ _ init _ _ frame has 5 items, including the return address and return value.
The RA is 37.
Self points to the first Point object on the  heap, the same point that p1 in main points to.
The variable x is 2.
The variable y is 1.
The RV points to the same Point object on the heap that self points to. 
The next Point # _ _ init _ _ frame has 5 items, including the return address and return value.
The RA is 38. 
self points to the second Point object on the heap, the same Point object that p2 in main points to.
The variable x is 3.
The variable y is 6.
RV points to the same Point object on the heap that self points to.
The Path # _ _ init _ _ frame has 5 items, including the return address and return value. 
The RA is 40.
self points the path object on the heap, which line 1 and line 2 in main point to.
The variable a points to the space for the value of a in the Path object.
The variable b points to the space for the value of b in the Path object.
The RV points to the Path object on the heap, which self points to.
The Path # translate frame has 2 items, including the RA.
The RA is 43. 
Self points to the path object on the heap, which is the same one that line 1 and line 2 in main point to.
The Path # scale frame has 3 items, including the RA. 
The RA is 44. 
Self points to the Path object in the heap, which is the same one that line 1 and line 2 in main point to.
The amount variable is assigned 2.
The heap includes 2 class objects, 1 function object, 2 Point objects, and 1 Path object.
The first line of the output is 14, 3. The second line is 14, 3.

  1. The memory diagram has three columns, labeled stack, heap and output.
The stack includes 9 frames including globals, main, Phone # _ _ init _ _, Phone # _ _ init _ _, Phone # _ _ init _ _, Phone # add _ contact, Phone # add _ contacts _ friends, Phone # add_ contact, and Phone # add _ contacts _ friends. 
The globals frame has 2 items.
Phone points to a Class on the heap from lines 6 to 32.
main points to a function on the heap from lines 35 to 45. 
The main frame has 5 items including the return address and return value.
The RA is 49.
The RV is None.
The variable main _ character points to a Phone object on the heap. The Phone object has the following attributes: number with the value of 919-999-9999, name with the value of Johnny, and contacts which points to list of Phones on the heap. The contacts at index 0 points to another Phone object on the heap with the number 704-999-9999, the name Bianca, and contacts pointing to another list on the heap. Index 1 of the contacts for Johnny and index 0 of the contacts for Bianca point to the same Phone object on the heap with the number 877 CASH NOW, the name Wentworth, and an empty list of contacts. 
Next in the main frame, the new_friend variable points at the phone object on the heap with the name attribute of Bianca.
The tv_ad variable in the main frame points at the phone object on the heap with the name attribute of Wentworth.
The Phone # _ _ init _ _ frame has 5 items including the return address and return value.
The RA is 36.
the RA and self points to the the phone on the heap with the name Johnny
The variable number has the value of the string '919-999-9999'
The variable name has the value of the string 'Johnny'
The next Phone # _ _ init _ _ frame has 5 items including the return address and return value.
The RA is 38.
the RA and self points to the the phone on the heap with the name Bianca
The variable number has the value of the string '704-999-9999'
The variable name has the value of the string 'Bianca'
The next Phone # _ _ init _ _ frame has 5 items including the return address and return value.
The RA is 39.
the RV and self points to the the phone on the heap with the name Wentworth
The variable number has the value of the string '877CASHNOW'
The variable name has the value of the string 'Wentworth'
The Phone # add _ contact frame has 4 items, including the return address and return value.
The return address is 40.
The return value is None.
self points to the Phone object on the heap with the name Bianca
other points to the Phone object on the heap with the name Wentworth
The Phone # add _ contacts _ friends frame has 5 items, including the return address and return value.
The return address is 42.
The return value is None.
self points to the Phone object on the heap with the name Johnny
Other points to the Phone object on the heap with the name Bianca
the contact variable has no value.
The Phone # add _ contact frame has 4 items, including the return address and return value.
The return address is 44.
The return value is None.
self points to the Phone object in the heap with the name Johnny
other points to the Phone object in the heap with the name Bianca
The Phone # add _contacts _ friends frame has 5 items, including the return address and return value. 
The return address is 45.
The return value is None.
self points to the Phone object on the heap with the name Johnny
other points to the Phone object on the heap with the name Bianca.
the contact variable points to the Phone object pointed to by index 0 of the contacts for Bianca, aka the Phone object with the name Wentworth.
The output has two strings. The first is 'Gotta find a way into the group somehow, Johnny.', and the second is the string 'Now that's quite a circle you're building!.'


The memory diagram has three columns labeled Stack, Heap, and Output.
The Stack frame has 4 frames, including globals, main, curve, and grading _ scale. 
The globals frame has 3 items.
Main points to a function on the heap on lines 4 to 9.
curve points to a function on the heap on lines 12 to 21.
grading _ scale points to a function on the heap from lines 24 to 25.
The main frame has 4 items, including the return address and return value.
The RA is 49.
The RV is None.
The variable student _ grades points to a dictionary on the heap with string keys and int values. The key 'Andre' has the crossed out initial value of 92, and the final value of 100. Key 'Jonny' has an initial value of 79 and a final value of 87. The key 'Ania' has the initial value of 86 and the final value of 94. The key 'Wendy' has the initial value of 55 and final value of 63. 
The variable letter _ grades points to a dictionary on the heap with string keys and string values. The key 'Andre' has the value 'A', the key 'Jonny' has the value 'B', the key 'Ania' has the value 'A', and the key 'Wendy' has the value 'D'.
The curve frame has 6 items, including the return address and return value.
The RA is 7. 
The RV is None.
The variable number _ grades points to the same dictionary on the heap that student _ grades in main points to.
The variable max has a previous value of 0 and a final value of 92.
The variable curve _ amount has a value of 8
The variable student has previous values of 'Andre', 'Jonny', 'Ania', 'Wendy', 'Andre', 'Jonny', 'Ania', and 'Wendy'.
The grading _ scale frame has 5 items, including the return address and return value.
The RA is 8.
The variable number _ grades points to the same dictionary in the heap as student _ grades in main and number _ grades in curve points to.
The RV and gradebook variable point to the same dictionary in the heap that letter _ grades in main points to.
The variable student has previous values of 'Andre', 'Jonny', 'Ania', and 'Wendy'.
The output is the dictionary with key-value pairs 'Andre': 'A', 'Jonny': 'B', 'Ania': 'A', and 'Wendy': 'D'.

Class Writing

    """Diagraming practice for Quiz 03."""

    class ChristmasTreeFarm:
        """A christmas tree farm!"""

        plots: list[int]

        def __init__(self, plots: int, initial_planting: int) -> None:
            """Sets up the farm."""
            self.plots = []
            i: int = 0
            while i< initial_planting:
                self.plots.append(1)
                i += 1
            while i < plots:
                self.plots.append(0)
                i += 1
        
        def plant(self, plot_number: int) -> None:
            """Plants a tree at the given plot number."""
            self.plots[plot_number] = 1
        
        def growth(self) -> None:
            """Grows each planted tree."""
            i: int = 0
            while i < len(self.plots):
                if self.plots[i] != 0:
                    self.plots[i] += 1
                i += 1

        def harvest(self, replant: bool) -> int:
            """Harvest trees that are fully grown!"""
            total: int = 0
            i: int = 0
            while i < len(self.plots):
                if self.plots[i] >= 5:
                    total += 1
                    if replant:
                        self.plots[i] = 1
                    else: 
                        self.plots[i] = 0
                i += 1
            return total

        def __add__(self, rhs: ChristmasTreeFarm) -> ChristmasTreeFarm:
            """Overload addition to create new ChristmasTreeFarm."""
            trees: int = 0
            for plot in self.plots:
                if plot > 0:
                    trees += 1
            for plot in rhs.plots:
                if plot > 0:
                    trees += 1
            return ChristmasTreeFarm(len(self.plots) + len(rhs.plots), trees)

Function Writing

    def find_courses(courses: list[Course], prereq: str) -> list[str]:
        """Finds 400+ level courses with the given prereq."""
        results: list[str] = []

        for c in courses:
            if c.level >= 400:
                for p in c.prerequisites:
                    if p == prereq:
                        results.append(c.name)
        
        return results
    def is_valid_course(self, prereq: str) -> bool:
        """Checks if this course is 400+ level and has the given prereq."""
        if self.level < 400:
            return False
        else: 
            for p in self.prerequisites:
                if p == prereq:
                    return True
            return False
Contributor(s): Megan Zhang, David Karash, Alyssa Byrnes