Creating Class Objects in Loop

Discussion in 'Python' started by Fish, Mar 30, 2008.

  1. Fish

    Fish Guest

    Hello Folks,
    I am reading a CSV file and based on that I am creating TestCase(my
    own defined class) objects in a for loop. The problem is each time I
    create a new TestCase object in loop, previous objects data is already
    copied in that object.

    e.g. my sample CSV file is
    # -------------------------
    hello.pcap, 123, 231
    test.pcap, 90, 899
    hello2.pcap, 81, 18
    # -----------------------

    When I print the TestCase elements from returned list I get

    (Pdb) print tcLstOrig[0]
    Pcap Path: hello.pcap
    Sid List: 123, 231, 90, 899, 81, 18,

    (Pdb) print tcLstOrig[1]
    Pcap Path: test.pcap
    Sid List: 123, 231, 90, 899, 81, 18,

    (Pdb) print tcLstOrig[2]
    Pcap Path: hello2.pcap
    Sid List: 123, 231, 90, 899, 81, 18,


    Kindly guys advise me on this thing. Function snippet and Class
    definition are provided below.

    Regards,
    Fish

    ======= Problem Code

    The function snippet reading CSV and creating TestCase objects is
    Code:
    tcLst = []
    # CSV file is read in variable 'lines'
    def returnTcLst(path):
      fp = open(path)
      lines = fp.readlines()
    
      for line in lines:
    	tc = TestCase()
    	i = line.find(",")
    	tc.setPcap(line[:i].strip())
    	line = line[i+1:]
    	line = line + ","
    	i = line.find(",")
    	while i != -1:
    		sid = line[:i].strip()
    		tc.appendSid(sid)
    		line = line[i+1:]
    		i = line.find(",")
    
    	tcLst.append(tc)
    	del tc
      return tcLst
    
    My TestCase Class is defined as
    Code:
    class TestCase(object):
    	def __init__(self, pcap = None, sids = []):
    		self.__Pcap = pcap
    		self.__lstSid = sids
    
    	def setPcap(self, path):
    		self.__Pcap = path
    
    	def appendSid(self, sid):
    		self.__lstSid.append(sid)
    
    	def __str__(self):
    		text = "Pcap Path: " + self.__Pcap + "\n"
    		text += "Sid List: "
    		for sid in self.__lstSid:
    			text += sid + ", "
    		text += "\n"
    		return text
    
    Fish, Mar 30, 2008
    #1
    1. Advertising

  2. En Sun, 30 Mar 2008 19:59:14 -0300, Fish <> escribió:

    > Hello Folks,
    > I am reading a CSV file and based on that I am creating TestCase(my
    > own defined class) objects in a for loop. The problem is each time I
    > create a new TestCase object in loop, previous objects data is already
    > copied in that object.


    See this FAQ entry:
    http://www.python.org/doc/faq/general/#why-are-default-values-shared-between-objects

    > ======= Problem Code
    >
    > The function snippet reading CSV and creating TestCase objects is
    >
    Code:
    > tcLst = []
    > # CSV file is read in variable 'lines'[/color]
    
    Try to use the standard csv module instead; it's fairly easy.
    [color=blue]
    > def returnTcLst(path):
    >   fp = open(path)
    >   lines = fp.readlines()
    >   for line in lines:[/color]
    
    Instead of those two lines, you could use:
    
         for line in fp:
    
    (readlines() has to read the whole file into memory; files are their own  
    line iterators)
    [color=blue]
    > 	tc.setPcap(line[:i].strip())[/color]
    
    getters/setters are not usually used in Python because they offer no  
    advantage over directly using an attribute:
    
             tc.pcap = line[:i].strip()
    [color=blue]
    > 	tcLst.append(tc)
    > 	del tc[/color]
    
    Why "del tc"?
    That doesn't invoke the destructor, just removes the name "tc" from the  
    local namespace. (The object tc refers to isn't destroyed yet because it  
    has at least one reference: it's contained in the tcLst list)
    [color=blue]
    > class TestCase(object):
    > 	def __init__(self, pcap = None, sids = []):
    > 		self.__Pcap = pcap
    > 		self.__lstSid = sids[/color]
    
    As you can see in the FAQ entry, the common idiom is to write:
    
      	def __init__(self, pcap = None, sids = None):
                     if sids is None:
                         sids = []
      		self.Pcap = pcap
      		self._lstSid = sids
    
    Note that I've changed the __names; use __ when you expect a name  
    collision with a subclass.
    For "implementation only" attributes, use a single underscore; based on  
    your appendSid method, lstSid looks like it's used in this way.
    [color=blue]
    > 	def setPcap(self, path):
    > 		self.__Pcap = path[/color]
    
    This method isn't necesary anymore.
    [color=blue]
    > 	def appendSid(self, sid):
    > 	def __str__(self):[/color]
    
    Should be changed accordingly.
    
    -- 
    Gabriel Genellina
    Gabriel Genellina, Mar 31, 2008
    #2
    1. Advertising

  3. Fish

    John Nagle Guest

    Fish wrote:
    > Hello Folks,
    > I am reading a CSV file and based on that I am creating TestCase(my
    > own defined class) objects in a for loop. The problem is each time I
    > create a new TestCase object in loop, previous objects data is already
    > copied in that object.


    What's actually happening to you is that you've run into one of the
    dumber features of Python - default values for parameters which are
    mutable, like lists, result in rather unexpected behavior. The
    problem is that

    def __init__(self, pcap = None, sids = []):

    creates the empty list "[]" once at startup, and that list is
    persistent across calls to __init__. Yes, that's wierd, but
    Python does that for historical reasons.

    Actually, you can write your main loop much more simply:

    def returnTcLst(path):
    fp = open(path)
    for line in fp:
    fields = line.split(",") # split into list at commas
    fields = map(lambda(s) : s.strip(), fields) # strip whitespace
    tcLst.append(TestCase(fields[0], fields[1:])) # pcap, then sids

    John Nagle
    John Nagle, Mar 31, 2008
    #3
  4. On Sun, 30 Mar 2008 21:34:00 -0700
    John Nagle <> wrote:
    > What's actually happening to you is that you've run into one of the
    > dumber features of Python - default values for parameters which are
    > mutable, like lists, result in rather unexpected behavior. The
    > problem is that
    >
    > def __init__(self, pcap = None, sids = []):


    I have never liked using that form for different reasons so I never
    tripped over that. Now I have another reason to avoid it. It's not a
    huge deal to do this.

    def __init__(self, pcap = None, sids = None):
    if sids is None: sids = []

    --
    D'Arcy J.M. Cain <> | Democracy is three wolves
    http://www.druid.net/darcy/ | and a sheep voting on
    +1 416 425 1212 (DoD#0082) (eNTP) | what's for dinner.
    D'Arcy J.M. Cain, Mar 31, 2008
    #4
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Replies:
    7
    Views:
    18,175
  2. 7stud
    Replies:
    11
    Views:
    689
    Dennis Lee Bieber
    Mar 20, 2007
  3. News123
    Replies:
    7
    Views:
    379
    Dave Angel
    Jun 29, 2009
  4. Arans
    Replies:
    0
    Views:
    588
    Arans
    Dec 14, 2011
  5. Isaac Won
    Replies:
    9
    Views:
    371
    Ulrich Eckhardt
    Mar 4, 2013
Loading...

Share This Page