Python Forum

Full Version: Help - Functions With While Loops
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Cheers! I'm a self-learning beginner using a crash course book. One of the "Try It Yourself" at the end of the chapter has me create a function with a while loop that prompts for your record. At the end you should be able to print the dictionary.

It works fine until I add a break statement. It inserts the "q" response as one of the values in the dictionary.

# This is the definition
def make_album(artist, album, tracks=''):
    """Return a dictionary of artist album info"""
    music = {
        'artist': artist, 
        'album': album,
        }
    if tracks:
        music['tracks'] = tracks
    return music

# This is the while Loop
while True:
    print("\nPlease tell me your favorite band and record.")
    print("(Enter 'q' at any time to quit)")

    b_name = input("Band name: ")
    if b_name == 'q':
        break
    
    a_name = input("Album name: ")
    if a_name == 'q':
        break

record = make_album(b_name, a_name)
print(record)
Output:
Please tell me your favorite band and record. (Enter 'q' at any time to quit) Band name: the cult Album name: electric Please tell me your favorite band and record. (Enter 'q' at any time to quit) Band name: q {'artist': 'q', 'album': 'electric'}
I'm not sure what the goal of the exercise is, so I'm not sure what the fix is, although I can see the problem. You are making the dictionary after the loop is done. So whatever values are in a_name and b_name will be what goes in the dictionary. Since this is after the loop is done, it is after you quit, and one of those must be 'q'.

Now, you could indent line 25 so it is part of the loop. Then, if you quit, it will skip making the dictionary with a 'q' value. However, that will remake the dictionary each time through the loop, overwriting anything stored in previous iterations of the loop. Normally you would start with an empty dictionary and add something to it each time through the loop, so that everything you enter is stored at the end. But I'm not sure what the dictionary should look like at the end, so I can't give advice on how to construct it.
Thanks for the response.

The goal of the exercise is to continuously prompt the user for their favorite band and album until the user enters "Q" which should end the while loop. All of the responses should fill the dictionary. Once the loop has finished it should then print the dictionary which contains a list of all the values that were entered. For example:

Output:
Please tell me your favorite band and record. (Enter 'q' at any time to quit) Band name: the cult Album name: electric Please tell me your favorite band and record. (Enter 'q' at any time to quit) Band name: the police Album name: synchronicity Please tell me your favorite band and record. (Enter 'q' at any time to quit) Band name: q {'artist': 'the police', 'album': 'synchronicity'}
It's a cheesy assignment, but I can't figure out how to stop the loop without populating the dictionary with the quit value.

Indenting line 25 does work. The dictionary no longer has the "q", but the code is supposed to print a dictionary for each set of values entered.
They problem was in the last 2 lines.
record = ... and print should be inside the loop and not outside.
So if you break out of the loop, the variable b_name or a_name does not exist.
If you want to append more than one album persistent, you can use a list for all results.
You can also use a list for tracks. A str is the wrong datatype to have an ordered sequence.


Another thing is, that you can lower the input-string, then you can also use Q for quit.
You can also check, if a string is empty:
my_string = '' # is empty
if not my_string:
    print('my_string is empty')
Your code a bit modified.
import json
from pprint import pprint


def make_album(artist, album, tracks=None):
    """Return a dictionary of artist album info"""
    music = {
        'artist': artist, 
        'album': album,
        'tracks': [],
        }
    # tracks is now always as key available
    # but if the tracks was None, it's an empty list
    if tracks:
        music['tracks'] = tracks # tracks should be a list, not a str
    return music


def ask_tracks():
    print('Please enter the tracks.')
    tracks = []
    while True:
        track = input('Track: ')
        if not track or track.lower() == 'q':
            break
        tracks.append(track)
    return tracks


def ask_band_album_loop():
    records = []
    while True:
        print("\nPlease tell me your favorite band and record.")
        print("(Enter 'q' or just enter at any time to quit)")
    
        b_name = input("Band name: ")
        if not b_name or b_name.lower() == 'q':
            break
        
        a_name = input("Album name: ")
        if not a_name or a_name.lower() == 'q':
            break
        
        tracks = ask_tracks()
        record = make_album(b_name, a_name, tracks)
        records.append(record)
        print(record)
    return records


if __name__ == '__main__':
    records = ask_band_album_loop()
    pprint(records)
    with open('music_data.json', 'w') as fd:
        json.dump(records, fd, indent=4)
    print('Result has been written as json to "music_data.json"')
(Oct-26-2019, 03:11 PM)pdub787 Wrote: [ -> ]the code is supposed to print a dictionary for each set of values entered.

That's not what the example output you showed is doing. It just prints the last one at the end. So I'm still not clear on the desired result.

Also, you have a bug in your output. Ghost in the Machine is a much better album than Synchronicity, and it's more Pythonic.
Heh...you're right about that! it just happened to be on my record play at the time! :)

This gave me enough to meet the lesson requirements. I just wish the instructions were a little more specific on the required results.

Including the record and print statements in the loop got me what I needed. I thought that it was supposed to print all the dictionaries at the end. The instructions don't clearly state that, but I guess it was up to interpretation?

Thanks again for all the help and zenyatta mondatta!