Creating Class Objects in Loop

F

Fish

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
 
G

Gabriel Genellina

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'[/QUOTE]

Try to use the standard csv module instead; it's fairly easy.
[QUOTE]
def returnTcLst(path):
fp = open(path)
lines = fp.readlines()
for line in lines:[/QUOTE]

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)
[QUOTE]
tc.setPcap(line[:i].strip())[/QUOTE]

getters/setters are not usually used in Python because they offer no  
advantage over directly using an attribute:

         tc.pcap = line[:i].strip()
[QUOTE]
tcLst.append(tc)
	del tc[/QUOTE]

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)
[QUOTE]
class TestCase(object):
	def __init__(self, pcap = None, sids = []):
		self.__Pcap = pcap
		self.__lstSid = sids[/QUOTE]

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.
[QUOTE]
def setPcap(self, path):
		self.__Pcap = path[/QUOTE]

This method isn't necesary anymore.
[QUOTE]
def appendSid(self, sid):
	def __str__(self):[/QUOTE]

Should be changed accordingly.
 
J

John Nagle

Fish said:
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
 
D

D'Arcy J.M. Cain

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 = []
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top