2010-03-05 8 views
0

J'ai ce code:entrées de la liste Python sont remplacées par la dernière entrée en annexe

def __parse(self):   
    for line in self.lines: 
     r = Record(line) 
     self.records[len(self.records):] = [r] 
     print self.records[len(self.records)-1].getValue() # 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() 

maintenant ce qu'il doit faire est de faire des disques de lignes de texte. Mais quand j'accède à la liste après que la boucle for ait été complétée, tous les enregistrements donnent les mêmes résultats pour les méthodes que j'appelle. Lorsque j'accède à un enregistrement à l'intérieur de la boucle for-right juste après qu'il a été ajouté, c'est le bon, donc l'enregistrement init ne peut pas être la faute. Non, c'est absolument certain que les lignes que je mets sont différentes! Quelqu'un at-il une idée pourquoi cela arrive? L'aide serait très appréciée!

+0

Pourquoi ne faites-vous pas juste self.records.append (r)? – FogleBird

+0

Pourriez-vous nous montrer comment 'Record' est défini? Si 'Record' stocke' line' comme un attribut de classe plutôt qu'un attribut d'instance, cela peut expliquer le problème. – unutbu

+0

Vous ne vérifiez que le * dernier * enregistrement dans la boucle. Qu'en est-il des valeurs précédentes? –

Répondre

1

Ahue, vous avez des objets mutables dans le partagé espace de noms de classe - une idée fausse très répandue lorsque vous démarrez avec python.Déplacer l'initialisation de records = [] dans CsvSet dans sa fonction __init__, et déplacez record = {} en Record__init__ fonction. Devrait ressembler à ce qui suit:

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

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

Lorsque vous déclarez une variable mutable dans la zone de classe, il est partagé entre toutes les instances de ces classes, pas créées pour chaque instance. En déplaçant l'initialisation dans une méthode d'instance (__init__ dans ce cas), vous créez de nouveaux magasins mutables pour chaque instance, ce que vous avez prévu.

+0

Merci beaucoup. Je pensais que c'était comme en Java. Maintenant ça a l'air de marcher! – Ahue

1

Vous n'appliquez pas à self.records; vous l'écrasez toujours.

Utilisation:

self.records.append(r)

à la place.

Modifier: Peu importe. Voir le commentaire d'Ignacio Vasquez-Abrams. Je supprimerais cette réponse sinon pour cela.

+4

En fait, 'L [len (L):] = [X]' est une forme pathologique d'append. –

+0

C'est une obfuscation assez décent. –

+0

Ah, je le vois maintenant. Sensationnel. – danben

1

se fait-il encore si vous le remplacer par ce qui suit:

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

EDIT:

Quelque chose doit se tromper dans Record puisque le code il fonctionne, même si elle fait les codeurs expérimentés pleurent quand ils le lisent.

+0

Je pense aussi que c'est la classe Record() qui est cassée. Je me demande vraiment comment il est mis en œuvre ... Voir le 'self.records [len (self.records):] = [r] ' (valide!) Code Je suppose que cela peut être quelque chose de 'intelligent' aussi :) Problèmes similaires (écrasant certaines «autres» données) se produisent dans le cas de confusion de structure mutable vs immuable et par exemple lors de l'utilisation de listes comme arguments par défaut. –

0

La classe Record est cassée, vous renvoyez toujours le même objet.

Sans voir le code pour enregistrement, il est impossible de deviner

Peut-être que vous utilisez une liste ou un dict comme paramètre par défaut pour __init__ et revenir avec ce getValue().

Une autre possibilité est que getValue() renvoie un attribut de classe plutôt que d'une instance d'attribut

0

Ok, donc je vais poster le code pour la classe enregistrement des éclaircissements, aussi.

Record classe:

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") 

classe CsvSet:

records = [] 

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

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

La méthode __parse dans CsvSet est maintenant comment il était au commencement. J'ai changé si pour des raisons de débogage mais le résultat est le même. Et Ignacio vous avez raison, j'ai débuté avec Python il y a seulement 2 semaines ...

+1

Vous devriez éditer votre question originale au lieu d'ajouter ceci comme réponse. –

+0

Merci, je le ferai la prochaine fois. Pardon! – Ahue

1

La classe d'enregistrement est cassée. Vous utilisez une variable de classe (Record.record) au lieu d'un attribut d'instance. La variable de classe est une pour toutes les instances et vous voulez self.record différent pour chaque instance.

Déplacer les:

record = {} 
line = "" 

lignes dans le constructeur (en retrait sous def __init__(self,line):)