On the web there is a copy of the original ICStunes music manager program that you've been working on:
http://www.ics.uci.edu/~kay/python/ICStunes0.py
Open this file in a separate window; you will need to refer to it for this quiz.
Fill in each blank below with one data type from this group:
int float bool str
list namedtuple tuple set dict
Song Album Songdisplay
What data structure does this code use to represent:
Write the necessary code to sort the collection MUSIC
into alphabetical order by the album artist's name.
Following the existing code, this should consist of one
statement plus one short function definition.
def Album_artist(a: Album) -> str:
''' Return the artist field of the album
'''
return a.artist
MUSIC.sort(key=Album_artist)
Write the function Album_average_length that takes an album and returns
the average length in seconds of a song on that album (as a float).
If any of the functions already defined in the file are useful,
you should use them for full credit.
def Album_average_length(a: Album) -> float:
''' Return the average length in seconds of a song on the album
'''
if len(a.songs == 0):
return 0
else:
return Album_length(a) / len(a.songs)
Write the one statement that will sort the collection MUSIC in order by
the average length of each album's songs, greatest average first.
MUSIC.sort(key=Album_average_length, reverse=True)
The function top_n_played (the last definition in the file) uses
play_count_from_songdisplay as the key argument to the sort
method. Why doesn't it use Song_play_count instead?
Because top_n_played sorts a list of Songdisplays. If we're sorting
a list of Songdisplays, the key function we use has to take a
Songdisplay as its argument. (Recall that the function that's the
value of the key argument to sort() takes one of the objects being
sorted and returns a value based on that object, which is used for
comparisons during the sort). play_count_from_songdisplay does take
a Songdisplay, while Song_play_count takes a Song.
Below are two code segments; each one generates an execution error whose message is shown. Fix the code as simply as possible to remove the error and produce the intended result.
L = ['Huey', 'Dewey', 'Louie', 'Donald', 'Daisy']
for i in range(10):
print(L[i])
Traceback (most recent call last):
File "/ICS/31/Quizzes/Quiz Code/quiz8.py", line 3, in
print(L[i])
IndexError: list index out of range
for i in range(len(L)):
for duck in L:
print(duck)
# This code uses the ICStunes definitions
def songs_from_year(MC: 'list of Album', selected_year: int) -> 'list of Songdisplay':
''' Return a list of Songdisplays for all songs released in the specified year
'''
list_of_Songdisplays = all_Songdisplays(MC)
result = [ ]
for sd in list_of_Songdisplays:
if sd.year == selected_year:
result.append(sd)
return sd
print("Names of songs from 1969:")
songs_from_1969 = songs_from_year(MUSIC, 1969)
for each_song in songs_from_1969:
print(each_song.s_title)
Traceback (most recent call last):
File "/ICS/31/Quizzes/Quiz Code/quiz8.py", line 14, in
print(each_song.s_title)
AttributeError: 'str' object has no attribute 's_title'
The short answer here is that songs_from_year is supposed to return a list (of Songdisplays)
but instead it returns just a single Songdisplay. When we try to use that value as if it were
a list of Songdisplays, we get the error. The correction is to have the function return
result instead of sd.
Here's the complete chain of reasoning:
A message like 'str' objet has no attribute 's_title'
says that we're trying to apply s_title (which should give us the song title from a Songdisplay)
to something for which s_title doesn't make sense---that is, something that isn't a Songdisplay.
So where do we apply s_title? To each_song in the print statement. We EXPECT each_song to be
a Songdisplay, but it must not be. Where did we go wrong?
In the bottom for-loop, each_song takes on each item in songs_from_1969, which is the value
that was returned by songs_from_year. We EXPECT that to be a list of Songdisplays, but it
must not be---at least one thing in songs_from_1969 (and thus in what was returned by
songs_from_year) must NOT be a Songdisplay.
So we'd better look at what songs_from_year actually returns.
The songs_from_year function is supposed to return a list of Songdisplays.
But instead it returns sd, a single Songdisplay. The bottom for-loop in the calling
program iterates through the fields of that one Songdisplay; the fields in question are
strings; it makes no sense to take the s_title field of a single string, which is what
gave us the error.
The function returns sd, but it should return result. In fact, just
looking at the function definition might tell us that if we're familiar
with the pattern of building up a result by scanning through a list.
We set the result to empty, we go through the list appending what we
want to append, and then at the end we return the result. Here, we got
that wrong and returned the control variable of the for loop instead.
There's the mistake.