4

im trying to create diferent objects (using Clases and objects) and saving them in a file to edit or retrive them later. However this how it looks.

GlobalCategories=[]
GlobalContent=[]
def LoadData(x,y):
   import pickle
   with open('bin.dat') as f:
       x,y = pickle.load(f)


def SaveData(x,y):
   import pickle
   with open('bin.dat', 'wb') as f:
      pickle.dump([x,y], f)

def Loader(x,y):
     try:
          LoadData(x,y)
     except:
          SaveData(x,y)

and this the snippet that saves that shows how I save the info the lists (tema is the class and the other stuff are the methods of that class):

newtheme=Tema()
newtheme.setInfo_name(newstr)
newtheme.setInfo_code(newcode)
GlobalCategories.append(newtheme)
SaveData(GlobalContent,GlobalCategories)

X and Y are global lists where I store the objects.(i have noticed that it saves the direction in the memory of each object) when i first run it, it creates the file and saves the infomation on the file, however if I close it, try to run it again and load the info, the program erases the information, and creates the file again, so anything that was stored is gone.

I dont know if this is a propper way to store objects or if there{s a better way so any advice is very welcome.

@abernert: Thank you abarnert! what I want to do is to save a list with two lists inside. for example one list is going to save the a make (toyota, nisan etc) and the other list the car model(tundra, murano). now each element is an object wich i add to a list when created. newtheme=Theme() newtheme.setInfo_name(newstr) GlobalCategories.append(newtheme) this is how i save the object in the global list. GlobalCategories is one of those two list i want to load later after i have closed the program (it would be like the list of car companies from the example). Now, where i have the problem is loading the objects from the lists after i have closed and restarted the program, because i am able to retrive and edit them from the list when i have not closed the shell. I need to load and store the makes and the cars objects in the respective list once i start the program so i can manipulate them later. Thank you abernert once again!

Ale Rojas
  • 497
  • 2
  • 7
  • 17
  • 2
    Can you show the code that calls these functions? – Neil Jun 12 '13 at 23:18
  • Your `LoadData` function doesn't do anything useful; it just rebinds the local names `x` and `y`. You can't pass names "by reference" like that in Python. – abarnert Jun 12 '13 at 23:37
  • Meanwhile, using bare `except` clauses that don't log anything makes it very, very hard to debug your code. Change `Loader` to `except Exception as e:` and add a `print(e)` or something to see whether it's unexpectedly failing the `LoadData` and hitting the `SaveData` when you didn't want it to. – abarnert Jun 12 '13 at 23:40

2 Answers2

8

It's hard to know what the problem is without context of how you are trying to use your LoadData and SaveData functions. However, here is a little demo that does what I think you want.

import pickle
import random

def load_data():
    try:
        with open("bin.dat") as f:
            x, y = pickle.load(f)
    except:
        x, y = [], []
    return x, y

def save_data(data):
    with open("bin.dat", "wb") as f:
        pickle.dump(data, f)

if __name__ == "__main__":
    x, y = load_data()
    print x, y
    x.append(random.randint(1, 10))
    y.append(random.randint(1, 10))
    save_data([x, y])

OUTPUT FROM CONSECUTIVE RUNS

[] []
[9] [9]
[9, 10] [9, 9]
[9, 10, 2] [9, 9, 4]
[9, 10, 2, 5] [9, 9, 4, 1]
[9, 10, 2, 5, 6] [9, 9, 4, 1, 9]
[9, 10, 2, 5, 6, 10] [9, 9, 4, 1, 9, 1]
sberry
  • 128,281
  • 18
  • 138
  • 165
  • 1
    You really want `open("bin.dat", "rb")` in `load_data`. Otherwise, it will break on Windows if there happen to be any newlines in the binary pickle stream, etc. (And it won't work in 3.x, but your code is already explicitly 2.x anyway.) – abarnert Jun 12 '13 at 23:39
  • Thank You sberry let me try – Ale Rojas Jun 13 '13 at 00:20
0

It's hard to be sure, but I'm guessing your problem is that you're writing a binary file, then trying to read it back as text, and you're using Python 2.x on Windows.

In this code:

def LoadData(x,y):
    import pickle
    with open('bin.dat') as f:
        x,y = pickle.load(f)

If you happened to have any LF newline characters in the binary pickle stream, opening the file as text will convert them to CR/LF pairs. This will cause the pickle to be invalid, and therefore it'll raise an exception.

In this code:

def Loader(x,y):
     try:
          LoadData(x,y)
     except:
          SaveData(x,y)

… you just swallow any exception and save some empty values.

You probably only want to handle file-not-found errors here (IOError, OSError, or FileNotFoundError, depending on your Python version).

But you definitely want to put the exception into a variable to help debug your problem, like this:

def Loader(x,y):
     try:
          LoadData(x,y)
     except Exception as e:
          SaveData(x,y)

You can put a breakpoint on the SaveData line in the debugger, or just add a print(e) line and watch the output, to see why you're getting there.


Meanwhile, even after you fix that, LoadData will never do anything useful. Assigning x,y = pickle.load(f) just rebinds the local variables x and y. The fact that they have the same names as the local variables in Loader doesn't mean that Loader's variables get changed. Neither does the fact that they used to refer to the same values.

Python doesn't have "reference variables" or "output parameters". The normal way to do this is to just return values you want to pass back to the caller:

def LoadData():
    import pickle
    with open('bin.dat') as f:
        x,y = pickle.load(f)
    return x,y

And of course Loader has to call it properly:

def Loader(x,y):
     try:
          x,y = LoadData()
     except:
          SaveData(x,y)

And you have the exact same problem again in Loader, so you need to fix it again there, and in its caller.

abarnert
  • 354,177
  • 51
  • 601
  • 671
  • Thank you abarnert! what I want to do is to save a list with two lists inside. for example one list is going to save the a make (toyota, nisan etc) and the other list the car model(tundra, murano). now each element is an object. – Ale Rojas Jun 12 '13 at 23:59
  • It very rarely matters whether you're trying to save a list of 3 strings or a list of 2 lists of 7 and 9 strings respectively. Either way, the list is a single object, and pickleable, right? There's no need to manually try to save the two lists explicitly, just save the list they're in. – abarnert Jun 13 '13 at 00:13
  • Meanwhile, don't you want a list of models for each make, rather than just a list of all models and a list of all makes? (In other words, a dict mapping makes to lists of models.) – abarnert Jun 13 '13 at 00:14
  • Finally, it looks like you might be asking a followup question, but, if so, I don't understand what it is. Please be more explicit about what you're doing, what you expect, and what actually happens (ideally by editing your question to add nicely formatted code and sample data, or filing a new question, whichever seems more appropriate). – abarnert Jun 13 '13 at 00:15