2

I'm trying to make a phone book in python and I want to save all contacts in a file, encoded as JSON, but when I try to read the exported JSON data from the file, I get an error:

Extra data: line 1 column 103 - line 1 column 210 (char 102 - 209)

(It works fine when I have only one object in "list.txt")

This is my code:

class contacts:
    def __init__(self, name="-", phonenumber="-", address="-"):
        self.name= name
        self.phonenumber= phonenumber
        self.address= address
        self.jsonData=json.dumps(vars(self),sort_keys=False, indent=4)
        self.writeJSON(self.jsonData)

    def writeJSON(self, jsonData):
        with open("list.txt", 'a') as f:  
            json.dump(jsonData, f)


ted=contacts("Ted","+000000000","Somewhere")

with open('list.txt') as p:
    p = json.load(p)
    print p

The output in list.txt:

"{\n    \"phonenumber\": \"+000000000\", \n    \"name\": \"Ted\", \n    \"address\": \"Somewhere\"\n}"

Now, if I add another object, it can't read the JSON data anymore. If my way of doing it is wrong, how else should I export the JSON code of every object in a class, so it can be read back when I need to?

2 Answers 2

3

The reason this isn't working is that this code path gives you an invalid JSON structure. With one contact you get this:

{"name":"", "number":""}

While with 2 contacts you would end up with this:

{"name":"", "number":""}{"name":"", "number":""}

The second one is invalid json because 2 objects should be encoded in an array, like this:

[{"name":"", "number":""},{"name":"", "number":""}]

The problem with your code design is that you're writing to the file every time you create a contact. A better idea is to create all contacts and then write them all to the file at once. This is cleaner, and will run more quickly since file I/O is one of the slowest things a computer can do.

My suggestion is to create a new class called Contact_Controller and handle your file IO there. Something like this:

import json

class Contact_Controller:
    def __init__(self):
        self.contacts = []

    def __repr__(self):
        return json.dumps(self)

    def add_contact(self, name="-", phonenumber="-", address="-"):
        new_contact = Contact(name,phonenumber,address)
        self.contacts.append(new_contact)
        return new_contact

    def save_to_file(self):
        with open("list.txt", 'w') as f:
            f.write(str(self.contacts))

class Contact:
    def __init__(self, name="-", phonenumber="-", address="-"):
        self.name= name
        self.phonenumber= phonenumber
        self.address= address

    def __repr__(self):
        return json.dumps({"name": self.name, "phonenumber": self.phonenumber, "address": self.address})

contact_controller = Contact_Controller()

ted = contact_controller.add_contact("Ted","+000000000","Somewhere")
joe = contact_controller.add_contact("Joe","+555555555","Somewhere Else")

contact_controller.save_to_file()

with open('list.txt') as p:
    p = json.load(p)
    print(p)

I've also changed it to use the built in __repr__() class method. Python will call that method whenever it needs a string representation of the object.

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you! If I would also want to add a function that deletes a contact, meaning it removes (pop) the JSON data from list.txt, which should be my approach? I think I know how to remove an element like "phone number", but not how to remove the whole object (for example, removing everything about 'Joe')
Sure thing, this is pretty easy with the controller structure. Add a function to the class to remove the contact from the list: def delete_contact(self, contact): self.contacts.remove(contact) And at the end of the file do this to delete "Joe": contact_controller.delete_contact(joe) contact_controller.save_to_file()
0

in writeJSON, you opened the file for append (mode='a'), which works fine the first time, but not the subsequent calls. To fix this problem, open the file with overwrite mode ('w'):

        with open("list.txt", 'w') as f:

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.