[Tutor] Saving and loading data to/from files

Daniel Yoo dyoo@hkn.eecs.berkeley.edu
Sun, 3 Jun 2001 01:52:34 -0700 (PDT)


On Sun, 3 Jun 2001, Daryl G wrote:

> Unfortunatly, I don't know what a csv file is -sorry. I have tried the one 

A "csv" file is a file where all the fields as separated by commas.  It's
nice to save data like this because it's fairly easy to separate a
comma-separated line back into its pieces:

###
>>> line = 'Daryl,gman_95@hotmail.com,tutor@python.org'
>>> user, email, mailing_list = string.split(line, ',')
>>> user, email, mailing_list
('Daryl', 'gman_95@hotmail.com', 'tutor@python.org')
###

I'm not quite sure what each of the letters stand for though.  Comma
Separated... Vormat?  *grin* Many programs know how to write their output
in csv format.  For example, Microsoft Excel knows how to write
spreadsheets in csv.


This message will be long, but don't skip it because I think I found the
bug in your program.



> Unfortunatly, I don't know what a csv file is -sorry. I have tried the
> one line at a time approach, but from I could tell python wouldn't
> allow this wiht the list type. At least not with the file.write() . It
> would give an error with list variable. It said it was a read only
> character buffer. The write method only works with primitive types;
> not lists, tuples, or dictionarys.

Hmmm... can you show us how you're writing to the file?  That'll help us
give advice on how to get things working.



> I have, however, discovered that it is infact reading in the data from
> a file when I am using the pickle method. I verified this by adding a
> print statement in my opendata method and it showed that it had read
> in the data.

Ah, good!



> The problem appears to be in my function that displays the
> information. I can't figure out why it doesn't work Thanks.

Ok, let's take a look.


> #listdata method to display contents of Address book
> #will display info if just added, but will not display info if just
> #loaded from a file
> 
> def listdata():
>    i=0
>    total=len(L_Name)
>    print total
>    print "Names and phone numbers in database so far"
>    print
>    print """Last Name       First Name      PH#"""
> 
>    for i in range(total):
>        print L_Name[i],
>        print "         ",F_Name[i],
>        print "\t\t",PH_num[i]

>From what I can tell, this looks ok.  It's using global variables, which
always make me involuntarily nervous, but that's ok.  *grin*

What I think is going on is exactly global variable stuff.  Let's take a
look at the loading part of your program.

###
import pickle, string

F_Name=[]
L_Name=[]
PH_num=[]
total=0

#            [some code cut]
#opendata method
def opendata():
     filename=raw_input("Enter the name of the Addressbook you wish to 
open:
")
     file = open(filename,'r')
     (F_Name,L_Name, PH_num, total)=pickle.load(file)
###


Yes, the bug that you're running into has to do with local variable stuff.  
What I mean is that, in your opendata() function, you have the line:

     (F_Name,L_Name, PH_num, total)=pickle.load(file)

In functions, Python will expect the variables inside to be "local", and
that means that any changes you make to variables inside opendata() stay
isolated from the rest of the program.  Usually, this is a good thing,
because this sort of sandboxing keeps us from messing with another part of
a program accidently.  And you're seeing this because, as long as we're in
opendata(), we can see that the file loaded successfully.  But those
variables "outside" the sandbox, in Global-land, haven't been touched, so
that's why the listdata() doesn't show any changes.


In this case, what you want is to make the change to F_Name, L_name,
PH_num, and total to be "global", so that the rest of the program knows
that those variables changed.  What you'll need to do is add the line:

    global F_Name, L_Name, PH_num, total

at the very beginning of your opendata() function, which tells Python to
take off the sandbox for those specific variables.  With this change, your
opendata() will look like this:


###
def opendata():
     global F_Name, L_Name, PH_num, total
     filename=raw_input("Enter the name of the Addressbook you wish to 
open:
")
     file = open(filename,'r')
     (F_Name,L_Name, PH_num, total)=pickle.load(file)
###

and that should fix the bug.


Having said that, it's usually a good idea to avoid global variables.  
There are usually good ways of rearranging things so that globals aren't
necessary... but we can talk about that on another message.


Hope this helps!  If you have more questions, feel free to ask us.