Question

I'm storing the call to a class Task in an array in a .dat file. I'd like to read this file and reconstruct the class calls.

Here's the class that I'm using right now:

class Task:

    def __init__(self, name, timespent):
        self.name = name
        self.timespent = timespent

    def __repr__(self):
        return repr('Task("%s",%s)'%(self.name, self.timespent))

Here's the reading from the file:

task_list = []
with open("task_list2.dat", "r") as file:
    task_list = eval(file.readline())

Here's the writing to the file:

with open("task_list2.dat", "w") as outFile:
    print(repr(task_list), file = outFile)

And here's the contents of the file: ['Task("class",20)'] Where "class" is the name of the task.

I understand that the problem has to do with the single quotes around 'Task("class",20)' but I have no clue how to get rid of them. The error message I get says something along the lines of: "str object has no attribute 'name'"

How can I remove those quotes so that I can reconstruct the classes the next time that I read the file?

Was it helpful?

Solution

You really, really, really don't want to try to use repr and eval as a serialization format.

If you just used, say, pickle, you wouldn't have this problem at all:

with open("task_list2.dat", "wb") as outFile:
    pickle.dump(task_list, outFile)

with open("task_list2.dat", "rb") as file:
    task_list = pickle.load(file)

Much simpler, yes?


But if you want to know how to solve the immediate problem instead of making it irrelevant: You've got multiple problems in your __repr__ method, all of which need to be fixed if you want it to be round-trippable.

  • You generate a string representation… and then call repr on it. You want to return the string representation, not a string representation of the string representation. Just leave out the repr.
  • You should always delegate to the repr of sub-objects, not the str. If you're using %-formatting, that means using %r rather than %s.
  • Don't try to add quotes around things. That may happen to work if the object itself has no quotes, backslashes, invisible characters, etc. in it, but why rely on that? If you think you need quotes, it's pretty much always a sign that you broke the previous rule, and you should fix that instead.

Here's how you can write a round-trippable repr for this class:

def __repr__(self):
    return 'Task(%r, %r)' % (self.name, self.timespent))

And you can verify that it does what you want:

>>> t = Task('task name', 23.4)
>>> t
Task('task name', 23.4)
>>> eval(repr(t))
Task('task name', 23.4)

Of course in your particular example, just fixing the first problem (removing the spurious call to repr) would have gotten rid of the single quotes and made that particular example work. You could also hack around that on the read side by calling eval twice. Or, for this particular example, even by calling eval(s[1:-1]) or eval(s.strip("'")). But any "fix" like that is just going to make it harder to debug the general problems you're going to run into once you have, e.g., a name that isn't as simple as a single all-ASCII-letter word.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top