0

Python is the first langauge I'm learning and currently I'm studying file input/output systems for storing simple data. I've briefly done an exercise regarding simple writing and pickling. For my purposes, I would like to use simple writing, as I would like to edit my "save files".

I have been successful in storing and retrieving data when the data is a STRING. The problem is when I store my object, it stores it as this unreadable format:

<__main__.Character object at 0x0078FE10>

How can I turn this unreadable format above back in to my object? Does Python have a built-in function that allows this?

Or will I have to convert my object to a string, containing all important variables BEFORE writing in to my data file?

Edit: Oops, forgot the code!

class Character(object):
    def __init__(self,name,exp,atk):
        self.name = name
        self.exp = exp
        self.lvl = int(self.exp/100)
        self.health = 10
        self.atk = atk
        if atk == None:
            self.atk = lvl*1.5

    def stats(self):
        print(self.name, end=" is level ")
        print(self.lvl)
        print("with", self.health, "health")

And here's the reading part of the I/O system. You can see it reads the data > converts the string to a list > splits arguments in list > use arguments for object creation.

with open('charData', 'r') as data:
    data = data.read()  # Read the contents of the file into memory.
    print (data)

    my_list = data.splitlines()
    print (my_list[0])  # Print the list.
    char_data = ast.literal_eval(my_list[0])

new_character = Character(*char_data)

Then I have my own function to display object stats:

new_character.stats()

spits out

Harley is level 3
with 10 health

so as you can see, it works fine. but if I use "newFile.write(new_character)" which is essentially the string of the object, which is "<main.Character object at 0x0215FE10>" from above.

I've been messing with str in the object for the past hour, but haven't found a way to use that function to find a solution and looking for guidance from a more experienced person.

Edit for Matt Habel:

def __str__(self):
    print ("[\"", end="")
    print (self.name, end="")
    print ("\"", end=", ")
    print (self.exp, end="")
    print (",", end=" ")
    print (self.atk, end="")
    print ("]")

This outputs this:

["Harley", 300, 3]
    print(new_character)
TypeError: __str__ returned non-string (type NoneType)

My reasoning for making my own "list" is so I can use the "AST" module to define the list arguments. I would later convert the list above to "new_character2", and write it using this:

newFile = open("charData","w")
newFile.write(new_character2)

Now I use:

Instead of that complicated parsing from above, I'm using the return function.

    def export(self):
        self.name = str(self.name)
        self.exp = str(self.exp)
        self.atk = str(self.atk)
        matt_data = "[\"%s\", %s, %s]" % (self.name, self.exp, self.atk)
        return matt_data

matt_export = new_character.export()
print(matt_export)

spits out:

["Harley", 600, 3]

and get no error code!

Harry
  • 33
  • 9
  • can you post the code that defines the object? Inside the object there are different types of entities, methods & properties. You need to know the name of the property in the object to retrieve it. – DrBwts Jul 16 '15 at 15:29
  • what is your command to get that? This line shows you the object in memory and not the value. This does not mean your object is not readable. – jcs Jul 16 '15 at 15:31
  • 1
    You need to "serialize" objects to be able to save them to files. There are a number of popular formats for this: JSON and XML are the most common these days. – Barmar Jul 16 '15 at 15:31
  • I posted the code above – Harry Jul 16 '15 at 15:37
  • @jcs the command I used was "print (new_character)". I've found that the print gives the exact same output as if I were to write to the output file. This has given me suspicions that the "write" function, and correct me if I'm wrong, writes only strings to the file. – Harry Jul 16 '15 at 15:41

2 Answers2

1

That format is the default string representation that python gives to objects. You can check this by calling str(object) on an instance of one of your classes. If you want a readable string of your object, you can provide a custom __str__(self) method on your class. This will change your objects string representation that is output to your file.

As to your actual question about turning the default representation back into one of your objects: it's impossible. That's because all that the default representation tells you is the name of the object and the memory location where it is currently stored. Because memory is transient (it isn't available to your program across different times you run it), you can't take that memory address and turn it back into one of your objects.

If you want to do this, there are a few ways to go about it:

  1. You could provide a human readable __str__ method. This will output data that you can read and hopefully make it easy to parse back into an object. You'll have to do that by reading the object's string representation from the file, extracting the data necessary to create a new object, and then creating the object.
  2. You can look into serialization methods. This will output the object in a form that is easy for the computer to read and write, but you'll probably be unable to read it. There are lots of serialization libraries, but python provides the pickle library to do this out of the box.
  3. You can look into some human readable data formats like json, yaml, etc. Using one of these will provide you with both a human readable file and some great libraries for working with those files.
Matt Habel
  • 1,493
  • 2
  • 14
  • 35
  • 1. I have tried using the __str__ method to spit out variables in a template I made that is similar to a list. A sort of work around to this all. But similar to str, the __repr__ method gives me the "TypeError: __repr__ returned non-string (type NoneType)" whenever I try to print a variable. 2. I tried pickling, but it didn't work. When I recalled the pickled data, it gave me the exact same data from above(pickling vs. simple writing no difference). Based on what people are telling me, I need to serialize the object first. But shouldn't pickling serialize it automatically? – Harry Jul 16 '15 at 15:47
  • 1
    Can you post the your `__str__` and `__repr__` methods? They need to return strings, but it seems as if your methods aren't returning anything. Also, pickling has enough problems that I would suggest against using it. [It's slow, a security risk, and has other problems](http://www.benfrederickson.com/dont-pickle-your-data/) – Matt Habel Jul 16 '15 at 15:49
  • Hey @Matt, I edited the OP at the bottom with my "str" code for the object. I know just looking at it that this kind of code is terrible, but my reasoning behind this was to make a way to convert my variables to a readable format (storing them in to a look-alike list) so I can later use the "AST" module with python to get the arguments. After all, python wouldn't know I made a fake list. Is this solution kind of like duct-taping? – Harry Jul 16 '15 at 16:05
  • Your __str__ method doesn't return anything. You need to return a string from your method, not just print it out. Also, using an AST for this kind of parsing is a bit heavy handed. It will work definitely, but it's also much more difficult than needs to be. You may want to try something like `ClassName(var1=..., var2=..., var3=..., ...)`. This will allow you to easily see what class the object is, and the values of all the variables. – Matt Habel Jul 16 '15 at 16:12
  • print(new_character) does returns "["Harley", 300, 3]". When should I use this heavy-handed method over anything else? How can I look more in to the "className(Var1=..." is that a tuple? – Harry Jul 16 '15 at 16:17
  • Does it return it? Or does it print it out. If you do `print(str(new_character))`, do you print a `None` or do you print the representation? And my suggestion is just a string that is easy to read and easy to parse. AST's are more suited to parsing complicated grammars that need to be operated on after the fact. You're just parsing a string into an object then discarding everything about the parsing except for the resulting object. – Matt Habel Jul 16 '15 at 16:20
  • It says "returned" TypeError: __str__ returned non-string (type NoneType), so I'm guessing returns. Error codes are always bad so I'd really heavily prefer the representation if that means it'll give me the same without the error code. – Harry Jul 16 '15 at 16:22
  • That means that you're returning nothing. A function in python must return something, so when you don't explicitly say to return something, it will `return None`. I think you need to reread about how functions work in python as it seems like you don't understand the concept of returning from a function. [This](http://learnpythonthehardway.org/book/) is a very good introduction to programming through python. You should read through that to better your understanding of both the python language and programming in general. – Matt Habel Jul 16 '15 at 16:28
  • Thanks matt, would you mind taking one last look at the original post at the bottom, and see if you agree with what i just learned? And see if THAT is the correct usage of the return? – Harry Jul 16 '15 at 16:40
  • @Harry Thanks for naming a character after me! And yea, that is much better. That does exactly what it is supposed to - return a string representation of the object. Just a few things could be improved - Python has moved towards [format strings](https://docs.python.org/2/library/stdtypes.html#str.format) which are [more sophisticated and safer to use](http://stackoverflow.com/questions/5082452/python-string-formatting-vs-format). You should use those instead of the old str % vars syntax. This will allow you to clean up the extra variables there and make it much clearer what you're doing. – Matt Habel Jul 16 '15 at 16:48
  • Thank you for your help Matt ,especially for leading me to on the path to good practice. Thanks again mate, cheers! – Harry Jul 16 '15 at 17:11
  • If my answer was able to solve your problem you should [accept it so that others with the same question can find this information](http://meta.stackexchange.com/a/5235) – Matt Habel Jul 16 '15 at 17:14
0

To save the object you must serialize it. Depending on whether you're in Python 2.7.x or 3.x, you have different specific options, but here is the version of pickle docs that will help for 2.7.x.

Shawn Mehan
  • 4,513
  • 9
  • 31
  • 51
  • I'm using the latest python (3.x), interesting about serializing. Where can I read more about that? – Harry Jul 16 '15 at 15:38
  • Did you follow the link? At the top of the python.docs page is a drop-down that takes you to the documentation for whichever supported python you are using. – Shawn Mehan Jul 16 '15 at 15:42