Try -> NameError auch nach Zuweisung

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
BjoernLaemmerzahl
User
Beiträge: 22
Registriert: Sonntag 17. Mai 2015, 12:22

Hallo,

ich bin auf der Suche nach etwas Hilfe zur Selbsthilfe :) Leider weiß ich nicht, was ich am besten Googlen soll bei meinem Problem.

Folgendes Problem.

Ich lade in bestimmten Zeitintervallen eine Datei und möchte Unterschiede sehen. Dazu lade ich diese Datei (Tabelle) in eine Liste mit dictionaries , "plants" und "old_plants". Beim Starten der Python-Datei sollte selbstverständlich kein Vergleich stattfinden. Meine erste Idee war zu überprüfen ob "old_plants" bereits assigned ist. Wenn nicht, dann soll soll von der zuvor geladenen Datei eine Kopie mit dem Name "plants_old" erstellt werden.

Code: Alles auswählen

        try:
            plants_old
        except NameError:
            plants_old = plants[:]
            print "Name Error"


        for i in xrange(0, len(mylist)/5, 5):
                d = DictDiffer(plants_old[i], plants[i])
                print "Changed:", d.changed()
                print plants_old[0]["Affected"], plants[0]["Affected"]  

Das Problem ist aber, dass auch bei mehrmaligen ausführen immer der Zweig NameError ausgeführt wird, obwohl ja im ersten Durchgang dieser beseitigt sein sollte. Dadurch läuft natürlich auch mein Vergleich ins Leere, da "plants" immer "plants_old" ist.

Ich bin mir auch ziemlich sicher, dass man die Sache besser angehen könnte, aber ich weiß leider nicht wie.


Vielen Dank für eure Hilfe (und Geduld) :)
Sirius3
User
Beiträge: 17754
Registriert: Sonntag 21. Oktober 2012, 17:20

@BjoernLaemmerzahl: es gibt None um die Abwesenheit eines Wertes zu kennzeichnen. NameError sind bei Programmierfehler sinnvoll, nicht aber in normalen Programmen. Eine for-Schleife über einen Index ist ein Anti-Pattern - schonmal was von zip gehört?
BjoernLaemmerzahl
User
Beiträge: 22
Registriert: Sonntag 17. Mai 2015, 12:22

Puh, ich glaube ich muss hier nochmal ganz von vorne Anfangen.

Deine Vorschlag folgend habe ich bei der Initialisierung des Skiptes folgendes geschrieben:

Code: Alles auswählen

class Ui_Dialog(self, Dialog)

    def setupUi(self, Dialog):

        global plants_old
        plants_old = {}

    def meineFunktion

        if plants_old is None:
        plants_old = plants[:]
   else:
        print "pass"
    

Dann bekomme ich aber den Fehler:

Code: Alles auswählen

    if plants_old is None:
UnboundLocalError: local variable 'plants_old' referenced before assignment
Dabei habe ich doch "plants_old" global definiert .... :/
¨

Zu deinem Tip mit Zip. Ich habe eine Seite zu Anti-Patterns entdeckt. Bisher hatte ich keine Probleme mit for ... range. Aber die Argumente für die Vermeidung machen Sinn ...
Sirius3
User
Beiträge: 17754
Registriert: Sonntag 21. Oktober 2012, 17:20

@BjoernLaemmerzahl: Poste doch richtigen Python-Code. Warum machst Du Dir die Mühe, alles nochmal falsch abzutippen, statt einfach das zu kopieren, was Du tatsächlich ausführst. Mit dem, was Du da gepostet hast, muß man raten, was Du denn gemeint haben könntest und wo vielleicht der Fehler auftritt.

Du hast scheinbar eine Klasse, dann nutze sie auch. Vergiss das es soetwas wie "global" gibt, denn das macht ja, wie Du selbst erfahren hast, nur Probleme.
BjoernLaemmerzahl
User
Beiträge: 22
Registriert: Sonntag 17. Mai 2015, 12:22

Hallo,

da hast du natürlich recht.

Ich glaube ich habe es raus. Jedenfalls funktionert jetzt alles (sogar der Vergleich).

Code: Alles auswählen

class Ui_Dialog(object):

    def __init__(self):
        self.plants_old = {}

        if bool(self.plants_old) is False:
           print "None"
           self.plants_old = plants[:]
           print plants[0]["Affected"] 
           print self.plants_old[0]["Affected"] 

        else:
           print self.plants_old
           print "Valid"
           print plants[0]["Affected"]
           # print self.plants_old[0]["Affected"]  

        for i in xrange(0, len(mylist)/5, 5):
                d = DictDiffer(self.plants_old[i], plants[i])
                print "Changed:", d.changed()

Sirius, überall in Europa steht ein Freigetränk für dich bereit :)

Danke! Ich schaue mir jetzt mal die Anti-Patterns an.
Sirius3
User
Beiträge: 17754
Registriert: Sonntag 21. Oktober 2012, 17:20

@BjoernLaemmerzahl: sowas in __init__ zu schreiben ist wenig sinnvoll. self.plants_old wird immer ein leeres Dictionary sein. Diese umständliche if-Konstruktion sollte einfach "if not self.pants_old" heißen. Woher kommt denn "plants"? Es wird nicht als Argument übergeben!

Grundsätzlich muß man zwischen leeren Wörterbüchern, leeren Listen und dem Objekt None unterscheiden. Offensichtlich ist plants eine Liste, also macht es keinen Sinn, plants_old als Wörterbuch zu initialisieren. Auch mit einer leere Liste könnte man nicht zwischen einer uninitialisierten plants_old und einer Liste ohne Inhalt unterscheiden. Daher gibt es ja None: Wert nicht vorhanden.

Auch braucht man sich die Mühe, alle Elemente zu vergleichen, gar nicht machen, wenn man vorher die Liste kopiert.

So könnte es aussehen:

Code: Alles auswählen

class PlantsComparer(object):
    def __init__(self):
        self.plants = None

    def compare(self, plants):
        if self.plants is not None:
            for old, new in zip(self.plants, plants):
                d = DictDiffer(self.plants_old[i], plants[i])
                print "Changed:", d.changed()
        self.plants = plants
Antworten