1

I should begin by saying this is being run in IPython, using the Spyder IDE if it makes a difference. I am somewhat of a newbie at Python but fluent in other languages.

I have a class which is instantiated and used in a function, like below. I have simplified the code from a very long reading and processing algorithm. This all works fine the first time I run this file and call ReadFile(). Any subsequents runs crash, basically because m_seclist and m_headers already contain data.

My understanding of classes comes from C++, PHP and VB so I may be off with my assumptions, but as the class is instantiated within a function (ie local scope), should the instance not be completely destroyed at the end of the function? In this case it appears it very definitely isn't, or at least some of the variables are surviving. Am I misunderstanding how Python deals with class instances?

class Reader:
    m_headers = []
    m_seclist = []


    def __init__(self, filename):
        fh = open(filename, 'r')
        file_contents = fh.read().splitlines()
        fh.close()

        dataPointList = []

        for line in file_contents:
            for each section in the file (more code here)
                thisLine = line.split()
                dataPointList.append((float(thisLine[1]), float(thisLine[0])))
            m_seclist.append(dataPointList)
            dataPointList = []

    def getData(self, index):
        return m_seclist[index][0]

  #end of class
   def ReadFile(filename):
       my_instance = Reader(filename)
       output = my_instance.getData(2)
       return output

If I can clarify something, yell.

kasper Taeymans
  • 6,950
  • 5
  • 32
  • 51
Tom Kilney
  • 39
  • 2
  • 8
  • Could you clarify how you noticed that "some of the variables are surviving"? – glglgl Feb 11 '15 at 21:35
  • and where is the rest of your code? I don't see any object initiation. – kasper Taeymans Feb 11 '15 at 21:36
  • Essentially the ReadFile function crashes the second time it is run (ie run straight after the first time), and whilst debugging I printed the m_seclist lists to discover that they contained two copies of the data (e.g 1,2,3,1,2,3 where it should be 1,2,3) – Tom Kilney Feb 11 '15 at 21:36
  • @kasperTaeymans I think its the my_instance = Reader(filename) line, is this not the correct way to initialise a class? – Tom Kilney Feb 11 '15 at 21:37
  • 3
    Please read http://stackoverflow.com/q/1680528/3001761 – jonrsharpe Feb 11 '15 at 21:39
  • yes it is but your indentation is somewhat wrong... it seems that ReadFile is part of the class... but it isn't. – kasper Taeymans Feb 11 '15 at 21:39
  • I interpreted it as a separate function. There is no static method decorator. – Malik Brahimi Feb 11 '15 at 21:40
  • @TomKilney not quite. What we're talking about here is Class members and Instance members. There's a difference. Class members are available from all instances of that particular class. This is great for static values that are the same across all instances. Instance members are dynamic to each instance. – James Mertz Feb 11 '15 at 21:46
  • @TomKilney this is consistent, not crazy - everything else you define at the same level (e.g. the methods) belong to the class, not an instance. – jonrsharpe Feb 11 '15 at 21:47

2 Answers2

4

Your problem is the way you store the data:

Class attributes are stored in the class and shared between all instances of a class.

Instance attributes, instead, count per instance.

Instead of

class Reader:
    m_headers = []
    m_seclist = []


    def __init__(self, filename):

do

class Reader:
    def __init__(self, filename):
        self.m_headers = []
        self.m_seclist = []
        ...

Then they are new and fresh in every instance.

glglgl
  • 89,107
  • 13
  • 149
  • 217
1

You misunderstood class and instance members. What you do with this:

class Reader:
    m_headers = []
    m_seclist = []

is declare class members. And they survive.

What you want is this, oh and convention in python is to just prefix with _ private members. I've also added with statement which is preferred for handling resources that need closing.

class Reader:

    def __init__(self, filename):
        self._headers = [] # This creates instance members
        self._seclist = []
        with open(filename, 'r') as fh: # With statement will auto close fh
            file_contents = fh.read().splitlines()

        for line in file_contents:
            dataPointList = []
            for each section in the file (more code here)
                thisLine = line.split()
                dataPointList.append((float(thisLine[1]), float(thisLine[0])))
            self._seclist.append(dataPointList)

    def getData(self, index):
        return self._seclist[index][0]

def ReadFile(filename):
    my_instance = Reader(filename)
    output = my_instance.getData(2)
    return output
Th30n
  • 303
  • 1
  • 8