[Tutor] Looping over lists of objects

Danny Yoo dyoo at hkn.eecs.berkeley.edu
Mon Apr 24 20:16:03 CEST 2006



On Mon, 24 Apr 2006, Etrade Griffiths wrote:

> just feeling my way into Python with a small app that reads data from 
> file, creates objects using that data, stores the objects in a list, 
> loops over the list doing comparison tests to filter out various 
> objects.  Here is a code snippet:
>
> class myObj:
>    def __init__(self,a,b):
>        self.a=a
>        self.b=b
>
>    def get_a(self):
>        return self.a
>
>    def get_b(self):
>        return self.b

Hi Alun,

Looks ok so far.

Python specific tip: we can avoid writing getters and setters in Python. 
Python supports an alternative way to control how clients set and get 
attributes.  If you're interested, look for information on Python 
"properties".  So for now, I'd recommend simplifying this to:

##########################
class myObj:
    def __init__(self,a,b):
        self.a=a
        self.b=b
##########################

until we get into a real need to set up explicit get/set methods.


> # Read data from file
>
> L1=[]
> nobj=0
>
> for line in input:
>        L0=line.split()
>        a=L0[1]
>        b=L0[2]
>        nobj=nobj+1
>
>        an_obj=myObj(a,b)
>
>        L1.append(an_obj)

There must be additional context here, in the sense that I don't know what 
'input' is.  I suspect this is a file of some sort.  So unfortunately, we 
won't be able to test the exact same situation that you have.


I'd recommend turning this into a function as well, just to make the 
commend superfluous:

##########################
def read_data_from_file(input):
     L1=[]
     nobj=0
     for line in input:
        L0=line.split()
        a=L0[1]
        b=L0[2]
        nobj=nobj+1
        an_obj=myObj(a,b)
        L1.append(an_obj)
     return L1, nobj
##########################

If we have this function, we can then test by doing:

#####################################
L1, nobj = read_data_from_file(input)
#####################################

and preserve the original behavior of our program.  (We may want to do 
some additional revision --- the nobj variable is also superfluous.)


> Trying to debug this using IDLE.  The calls x.get_a and x.get_b always 
> return zero so something is going wrong somewhere.  I think I'm either 
> not storing the objects correctly or retrieving them correctly but no 
> idea why!  All suggestions gratefully received!!!

I don't see anything horribly wrong with the code.  There are at least two 
possibilities when a problem comes up:

     * There's something wrong with the program (which might be the case,
       although I don't see it yet.)

     * The input to the program is weird.

I'll assume, for the moment, that the input may be weird.  *grin*


If we do have read_data_from_file() as function, we can test it by passing 
it hardcoded "files", and see that we get the myObj values we expect.

Here's one test to start you off:

####################################################
import StringIO

def test1():
     sample_data = StringIO.StringIO("foo\tbar\tbaz\n")
     objs, nobjs = read_data_from_input(sample_data)
     assert (len(objs) == 1 == nobjs)
     first_object = objs[0]
     assert (first_object.a == "bar")
     assert (first_object.b == "baz")
####################################################

(This uses the very useful StringIO module to disguise a string to make it 
look like a file.  See: 
http://www.python.org/doc/lib/module-StringIO.html)

Does this test case make sense to you?

If this test works out ok, then we've still made progress: we can at least 
know that our parser is working well.  That bolsters the possibility that 
the input we're getting from our other source is weird.


Good luck to you.


More information about the Tutor mailing list