A music app's playlists should feel like lists: you can ask for their length, take the third track or the last five, loop over them, check whether a song is on them and join two of them. But a playlist is not just a list: it has a name, a total duration and its own way of printing itself.
Write two classes:
Track(title, artist, seconds): a record with those three fields, printed likeTrack(title='Hey', artist='Ola', seconds=185). Tracks with the same fields are equal and can be put in a set.Playlist(name, tracks=()), wheretracksis any iterable ofTrackobjects:len(p)is the number of tracks;p[i]is a track (negative indices count from the end; an index out of range raisesIndexError);p[i:j],p[::2]and every other slice give a newPlaylistwith the same name;for t in p,list(p)andreversed(p)go through the tracks;x in pisTrueifxis a track on the playlist, or a string equal to the title of one;p + qis a new playlist named"<p's name> + <q's name>"withp's tracks followed byq's;p.secondsis the total length in seconds, as an attribute without brackets;str(p)is"<name>: <n> tracks, <duration>"with1 trackfor a single track, and the duration asM:SS, orH:MM:SSfrom one hour.
Changing the iterable you passed in afterwards must not change the playlist. The setup's library(n, seed) returns a list of n generated tracks.
Examples
Input: p = Playlist("Road trip", [Track("Hey", "Ola", 185), Track("Go", "Kai", 240), Track("Up", "Ola", 200)])
len(p), p[-1].title, str(p[1:]), "Go" in p, [t.title for t in reversed(p)]
Output: (3, 'Up', 'Road trip: 2 tracks, 7:20', True, ['Up', 'Go', 'Hey'])
Input: str(p + Playlist("Extra", [Track("Long", "Mo", 3000)])), p.seconds
Output: ('Road trip + Extra: 4 tracks, 1:00:25', 625)
Constraints
- Up to
10**4tracks;secondsare positive integers.
Goals
- Make a class work with `len`, indexing, slicing, `for`, `in`, `reversed` and `+`
- Return an object of your own class from a slice or a sum, not a plain list
- Keep the tracks private behind the sequence interface