Search code examples
pythonfiledictionarywritetofile

Exporting a dictionary to a text file in this format



I am trying to export a dictionary to a text file as shown with the code below:

user_scores = {}

with open('Class 1.txt') as f:
    for line in f:
        this_line = line.strip().replace("\n","").split(",")
        user_scores[this_line[0]] = this_line[1:]

    username = "Andy.Singh"
    score = 25

    user_scores[username] = score

    print(user_scores)

    for user,score in user_scores:
        f.write(user + ',' + score)

The text file for Class 1.txt is shown so far:

Bob.Smith, 10, 20, 30

Here, the dictionary user_scores is having the username and scores of Bob.Smith written to it. I am also writing another new name, Andy.Singh who obtained a score of 25.

When I run the code, the dictionary writes the dictionary correctly as shown:

{'Andy.Singh': 25, 'Bob.Smith': [' 10', ' 20', ' 30']}

but the last write to text file doesn't work. I want to write to the same file, but this returns the error:

Traceback (most recent call last):
  File "/Users/Ahmad/Downloads/Manraj/test.py", line 15, in <module>
     for user,score in user_scores:
ValueError: too many values to unpack (expected 2) 

In simple words, I want the file to now show this:

Bob.Smith, 10, 20, 30
Andy.Singh, 25

How can I fix this error? Do I need to add other attributes that I am missing?

Thanks.


Solution

  • There's several things wrong with your code.

    The error you're getting is because:

    for user,score in user_scores:
    

    doesn't iterate over the contents of the dictionary like you seem to think. To do that properly you'd need to use something like:

    for user, scores in user_scores.items():
    

    The other problems have to do with the file handling. By default, open() only opens a file only for reading. To do both you need something like a mode of 'r+' which means reading and writing.

    Also in the loop where you write lines to the file needs to handle both the case where there list of scores as well as when there's only one. To simplify things I made adding / updating entries always create a list of values, even if that list consists of only one value. This makes it possible to only have to handle scores one way — since they'll always be lists — in the formatting done in the write() statement used to update the file.

    user_scores = {}
    
    with open('Class 1.txt', 'r+') as f:
        # read existing contents
        for line in f:
            this_line = [elem.strip() for elem in line.split(",")]
            user_scores[this_line[0]] = this_line[1:]
    
        # add or update an entry
        username = "Andy.Singh"
        score = 25
        user_scores.setdefault(username, []).append(str(score))
    
        print(user_scores)
    
        # rewrite file
        f.seek(0)  # rewind file
        for user, scores in user_scores.items():
            f.write('{}, {}\n'.format(user, ', '.join(s for s in scores)))
    

    Class 1.txt after running:

    Bob.Smith, 10, 20, 30
    Andy.Singh, 25
    

    Class 1.txt after changing score added to 30 and running again:

    Bob.Smith, 10, 20, 30
    Andy.Singh, 25, 30