This task is part of project07 which is due at 23:00 EDT on 2025-10-28.
You have the option to work with a partner on this task if you wish. Working with a partner requires more work to coordinate schedules, but if you work together and make sure that you are both understanding the code you write, you will make progress faster and learn more.
You can download the starter code for this task using this link.
You can submit this task using this link.
Put all of your work for this task into the file
listDiagrams.py
(which is provided among the starter files)
This task involves defining six functions whose purpose is to create lists described by specific memory diagrams.
Let's begin with a sample memory diagram and showing several ways
to define a function that creates it. Here's the diagram for
a list we'll call list0:
We'll consider three different approaches for defining a zero-parameter
function makeList0 that creates and returns the top list in the diagram.
makeList0: Use variables to name shared sublistsIn our makeList0 function, it's OK to define as many local variables as
we want to help us, even if they don't appear in the diagram.
We can use local variables to name shared sublists and then use
these variables to achieve the sharing we desire.
We'll introduce variables shared2, shared1, and top, as shown
in the following sequence of statements:
| Statements | Diagram so far |
|---|---|
shared2 = [2] |
|
shared1 = [1, shared2] |
|
top = [shared1, shared2, shared1, shared2] |
We can finish by encapsulating the steps for Approach 1 within a zero-parameter function makeList0:
def makeList0():
"""
Returns the top list depicted in the memory diagram for list0.
Uses Approach 1 to create the appropriate list structure.
"""
shared2 = [2]
shared1 = [1, shared2]
top = [shared1, shared2, shared1, shared2]
return top
makeList0: Use a single variable and assignment to list slotsA second approach for creating the list structure shown for list0 is to
use a single variable (call it top) to create an initial list with
four slots, where all slots but the last one contain bogus placeholder
values that will be replaced in subsequent steps. Then we use assignment
to list slots to create extra structure and achieve the desired result.
| Statements | Diagram so far |
|---|---|
top = [3, 4, 5, [2]] |
|
top[0] = [1, top[3]] |
|
top[1] = top[3]top[2] = top[0] |
We can finish by encapsulating the steps for Approach 2 within a zero-parameter function makeList0:
def makeList0():
"""
Returns the top list depicted in the memory diagram for list0.
Uses Approach 2 to create the appropriate list structure.
"""
top = [3, 4, 5, [2]]
top[0] = [1, top[3]]
top[1] = top[3]
top[2] = top[0]
return top
makeList0: Use a single variable and .appendA third approach for creating the list structure shown for list0 is to
use a single variable (call it top) and use only calls to
the list .append method to create the desired diagram using the following
steps:
| Statements | Diagram so far |
|---|---|
top = [[1]] |
|
top[0].append([2]) |
|
top.append(top[0][1]) |
|
top.append(top[0]) |
|
top.append(top[1]) |
We can finish by encapsulating the steps for Approach 3 within a zero-parameter function makeList0:
def makeList0():
"""
Returns the top list depicted in the memory diagram for list0.
Uses Approach 3 to create the appropriate list structure.
"""
top = [[1]]
top[0].append([2])
top.append(top[0][1])
top.append(top[0])
top.append(top[1])
return top
In the file listDiagrams.py, you will flesh out the definitions of six
functions that create and return a list. Each function must have zero
parameters and must return the top list for the structure depicted in the
associated memory diagram.
In all of your functions, it is OK to use as many local variables as
you want to name parts of the memory diagram, even though the memory
diagrams themselves do not show any variables. See the three versions
of makeList0 above for examples of using local variables
in this way.
In all of the functions, it is possible to use only a single local
variable (like top in Approaches 2 and 3 for makeList0).
If you want to give yourself an (ungraded) challenge, write your
solutions using at most one local variable.
makeList1The function makeList1 has zero parameters
and returns
a list with the following structure:
makeList2The function makeList2 has zero parameters
and returns
a list with the following structure:
makeList3The function makeList3 has zero parameters
and returns
a list with the following structure:
makeList4The function makeList4 has zero parameters
and returns
a list with the following structure:
makeList5The function makeList5 has zero parameters
and returns
a list with the following structure:
Note that this diagram contains some string values; "parent",
"child1", and "child2" are strings stored in list slots, not variable
names (variables are shown without quotes, have an associated box, and do
not have arrows pointing to them).
makeList6(Defining this function is an extra goal.)
The function makeList6 has zero parameters
and returns
a list with the following structure:
You cannot tell just from the printed output of your functions whether they
have the correct structure. For example, both list1 and list2 have
the printed representation:
[[1, 2], 3, [1, 2]]
The Python is operator (covered in Lec 11) is useful for determining
which sublists are shared an which are not. For example, executing
the statements
list1 = makeList1()
list2 = makeList2()
print('list1[0] is list1[2] =>', list1[0] is list1[2])
print('list2[0] is list2[2] =>', list2[0] is list2[2])
prints
list1[0] is list1[2] => False
list2[0] is list2[2] => True
By using suitable tests involving is (in conjunction with some other tests),
it is possible to determine if the lists returned by the six makeListn
functions have the correct structure.
As usual, we have supplied a test file test_listDiagrams.py which will
use optimism to check that your results are correct, including key
parts of their internal structure. We have also provided a file named
show_listDiagrams.py which will print out a "memory report" for the
result of each of your functions. This is kind of like a memory diagram
in text format, and you can compare these to the memory reports shown in
the examples below to see if things are correct.
In a memory report, each object gets assigned a label that starts with
@, and instead of drawing arrows when one object references another, we
write the label of the referenced object.
Examples for each function
Note that these examples show what the results look like as Python
values, which is not enough to know what their memory diagrams look like,
so each example also shows a memory report which shows how objects
reference each other. In a memory report, each object is assigned a tag
that starts with @, and when objects reference each other a tag is used
where an arrow would be used in a memory diagram.
In []:Out[]:makeList1()Memory Report[[1, 2], 3, [1, 2]]@0: [@1, 3, @2] @1: [1, 2] @2: [1, 2]In []:Out[]:makeList2()Memory Report[[1, 2], 3, [1, 2]]@0: [@1, 3, @1] @1: [1, 2]In []:Out[]:makeList3()Memory Report[[1, [[3], 2]], [[3], 2], [3]]@0: [@1, @2, @3] @1: [1, @2] @2: [@3, 2] @3: [3]In []:Out[]:makeList4()Memory Report[[4, 5], [[4, 5], [[4, 5], [4, 5]]], [[4, 5], [4, 5]], [4, 5]]@0: [@1, @2, @3, @4] @1: [4, 5] @2: [@1, @3] @3: [@1, @4] @4: [4, 5]In []:Out[]:makeList5()Memory Report['parent', [['child1', [...]], ['child2', [...]]]]@0: [@1, @2] @1: 'parent' @2: [@3, @5] @3: [@4, @0] @4: 'child1' @5: [@6, @0] @6: 'child2'In []:Out[]:makeList6()Memory Report[[7, [...], 8, [...]], 6, [7, [...], 8, [...]]]@0: [@1, 6, @1] @1: [7, @0, 8, @1]
makeList1 result looks the same
makeList1 must at least compare equal to the solution result, even if it has a different in-memory structure.makeList1 must have the correct memory structure
makeList1 must match that of the result produced by the solution code, including which parts are aliases of each other.makeList2 result looks the same
makeList2 must at least compare equal to the solution result, even if it has a different in-memory structure.makeList2 must have the correct memory structure
makeList2 must match that of the result produced by the solution code, including which parts are aliases of each other.makeList3 result looks the same
makeList3 must at least compare equal to the solution result, even if it has a different in-memory structure.makeList3 must have the correct memory structure
makeList3 must match that of the result produced by the solution code, including which parts are aliases of each other.makeList4 result looks the same
makeList4 must at least compare equal to the solution result, even if it has a different in-memory structure.makeList4 must have the correct memory structure
makeList4 must match that of the result produced by the solution code, including which parts are aliases of each other.makeList5 result looks the same
makeList5 must at least compare equal to the solution result, even if it has a different in-memory structure.makeList5 must have the correct memory structure
makeList5 must match that of the result produced by the solution code, including which parts are aliases of each other.makeList1 with 0 parameters
def to define makeList1 with 0 parametersreturn statement
makeList1 with 0 parameters, use return _ in at least one place.makeList2 with 0 parameters
def to define makeList2 with 0 parametersreturn statement
makeList2 with 0 parameters, use return _ in at least one place.makeList3 with 0 parameters
def to define makeList3 with 0 parametersreturn statement
makeList3 with 0 parameters, use return _ in at least one place.makeList4 with 0 parameters
def to define makeList4 with 0 parametersreturn statement
makeList4 with 0 parameters, use return _ in at least one place.makeList5 with 0 parameters
def to define makeList5 with 0 parametersreturn statement
makeList5 with 0 parameters, use return _ in at least one place.makeList6 must return the correct result
makeList6 function is run must match the solution result.makeList6 must have the correct memory structure
makeList6 must match that of the result produced by the solution code, including which parts are aliases of each other.makeList6 with 0 parameters
def to define makeList6 with 0 parametersreturn statement
makeList6 with 0 parameters, use return _ in at least one place.