开发者

Python list entries are overridden by last appended entry

I've got this code:

def __parse(self):        
    for line in self.lines:
        r = Record(line)
        self.records[len(self.records):] = [r]
        print self.records[len(self.records)-1].ge开发者_如何学编程tValue() # Works fine!
    print self.record[0].getValue() # Gives the same as
    print self.record[1].getValue() # as
    # ... and so on ...
    print self.record[len(self.record)-1].getValue()

Now what it should do is making records out of lines of text. But when I access those list after the for-loop has completed all records give the same results for methods I call on them. When I access a record within the for-loop right after it was appended it's the right one so the Record init can't be fault. No, it's absolutely sure that the lines I put in are different! Has anyone an idea why this happens? Help would be very appreciated!


Ahue, you have mutable objects in the shared class namespace -- a very common misconception when starting out with python. Move the initialization of records = [] in CsvSet into its __init__ function, and move record = {} into Record __init__ function. Should look like the following:

class Record:
    def __init__(self,lines):
        self.record = {}
        self.__parse()

class CsvSet:
    def __init__(self,lines):
        self.records = []
        self.__parse()

When you declare a mutable variable in the class area, it is shared among all instances of those classes, not created for each instance. By moving the initialization into an instance method (__init__ in this case), you are creating new mutable stores for each instance, which is what you intended.


Does it still happen if you replace it with the following:

self.record = [Record(l) for l in self.lines]

EDIT:

Something must be wrong in Record since the code there does work, even if it makes experienced coders weep when they read it.


You aren't appending to self.records; you are always overwriting it.

Use:

self.records.append(r)

instead.

Edit: Never mind. See Ignacio Vasquez-Abrams's comment. I would delete this answer if not for that.


Record class is broken. You use a class variable (Record.record) instead of an instance attribute. Class variable is one for all instances and you want different self.record for each instance.

Move the:

record = {}
line = ""

lines into the constructor (indented under def __init__(self,line):)


The Record class is broken, you are always returning the same object.

Without seeing the code for Record it's impossible to guess

Perhaps you are using a list or a dict as default parameter to __init__ and returning that with getValue().

Another possibility is that getValue() is returning a class attribute rather than an instance attribute


Ok, so I'll post the code for the Record class for clarification, too.

class Record:

record = {}
line = ""

def __init__(self,line):
    self.line = line 
    self.__parse()

def __parse(self):
    fieldnames = ['from','to','value','error']
    fields = self.line.split(',')

    c = 0
    for field in fields:
        self.record[fieldnames[c]] = field.strip()
        c+=1

    self.record['from'] = datetime.datetime.strptime(self.record['from'],"%Y-%m-%d")
    self.record['to'] = datetime.datetime.strptime(self.record['to'],"%Y-%m-%d")

class CsvSet:

records = []

def __init__(self,lines):
    self.__parse()

def __parse(self):        
    for line in self.lines:
        self.records.append(Record(line))

The __parse method in CsvSet is now how it was in the beginning. I changed if for debugging reasons but the result is the same. And Ignacio you're right, I startet with Python only 2 weeks ago...

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜