Ändern von Bezeichnungen in einer Liste

Code-Stücke können hier veröffentlicht werden.
Sirius3
User
Beiträge: 17703
Registriert: Sonntag 21. Oktober 2012, 17:20

@andyritter: es geht nicht darum, was Du jetzt mit diesen Datenstrukturen machst, sondern darum, was Du irgendwann einmal damit machst, und dann ist es immer sinnvoll, beim Programmieren so wenig Kollateralschäden anzurichten wie geht. Zudem Du weiter oben geschrieben hast, dass Du die anderen Keys noch umbenennen willst, so dass von Deinem ursprünglichen Wörterbuch nichts übrig bleibt.
Benutzeravatar
DeaD_EyE
User
Beiträge: 1011
Registriert: Sonntag 19. September 2010, 13:45
Wohnort: Hagen
Kontaktdaten:

Manchmal sind die Daten einfach zu sehr verschachtelt und man verliert schnell den Überblick. Zumindest geht es mir so.
Ich versuche das dann immer in der Repl auseinander zu nehmen. Wichtig ist, dass man genau weiß was für ein Datentypen vorliegen und welche bei der Iteration ausgegeben werden, damit man die passenden Methoden verwendet und überhaupt weiß was man dort macht. Also du hast ein dict, in dem der Schlüssel der Name der Liste ist und der Wert eine Liste mit Dicts.

Mit dict.items() liefert eine Tupel mit key, value (generator in Python3). Falls es Python2.7 ist, sollte man dict.iteritems() verwenden um Speicher zu sparen. Iteriert man über value nochmals, bekommt man die Elemente aus der Liste, die dicts sind. Dann noch im Hinterkopf behalten, dass dicts mutable Datentypen sind. D.h. Methoden, die du darauf anwendest, verändern das Objekt innerhalb der Liste. Die Liste ist natürlich auch mutable.

Code: Alles auswählen

l = {'List1': [{'description': 'What ever',
            'enabled': False,
            'id': '1234',
            'name': 'abc'},
           {'description': 'What ever2',
            'enabled': True,
            'id': '3456',
            'name': 'def'},
           {'description': 'What ever 3',
            'enabled': True,
            'id': '6789',
            'name': 'ghi'}],
 'Liste 2': []}

def change_state(data, id, enabled=False):
    for key, value in data.items():
        for item in value:
            if item.get('id') == str(id):
                item.update({'enabled': enabled})

change_state(l, 1234, True)
print([element for key, value in l.items() for element in value if element.get('id') == '1234'])
Am besten baust du dir eine Klasse um die Daten herum.
sourceserver.info - sourceserver.info/wiki/ - ausgestorbener Support für HL2-Server
Benutzeravatar
snafu
User
Beiträge: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

DeaD_EyE hat geschrieben:Am besten baust du dir eine Klasse um die Daten herum.
Falls damit gemeint ist, dass bloß triviale Getter und Setter für die einzelnen Schlüssel gebastelt werden sollen, um an den zugehörigen Wert zu kommen, dann würde ich den Einsatz von Klassen hier *nicht* empfehlen, weil ich den Mehrwert in diesem Fall für fragwürdig halte. Die Umsetzung deines Vorschlags findet man zwar oft z.B. in der Java-Welt, aber in Python ist es üblich, dass ein nacktes Dictionary Teil der API ist und dass deshalb keine Wrapper-Klasse um die Daten gebaut wird.

Falls etwas anderes gemeint ist, dann wären Details, wie diese Klasse aussehen soll bzw was sie tun soll, hilfreich.
Benutzeravatar
snafu
User
Beiträge: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

andyritter hat geschrieben:Der Hinweis mit der Kopie ist schon bei mir angekommen, doch ich benötige die Quelldaten ja nicht weiter, daher kann ich das meiner Meinung nach auch wirklich löschen.
Bei meiner Begründung stand die geringere Komplexität des Codes im Vordergrund, die man durch das Weglassen von `del`-Statements erreicht. Wie gesagt: Der zusätzliche Speicherverbrauch wirkt sich oft nicht spürbar aus, sodass der Vorteil, den man durch `del` zu haben glaubt, in der Praxis eigentlich nicht zum Tragen kommt. Zumal genau genommen gar nicht garantiert ist, wann ein durch `del` zum Löschen freigegebenes Objekt auch wirklich aus dem Speicher gelöscht wird. Das kann prinzipiell viel später passieren, als du denkst.

Aber gut: Letztlich ist es eine Frage des persönlichen Stils, ob man neue Dictionaries anlegt (und dadurch Codezeilen einspart) oder ob man lieber bereits bestehende Dictionaries verändert. Richtig schlecht wird der Einsatz von `del` erst bei Listen, weil dann unter Umständen (je nach Implementierung) intern eine Neuordnung der Daten erfolgen muss, wenn man mit `del` irgendwelche Elemente herausgepflückt hat. Und das ist dann gar nicht mehr so vorteilhaft in Hinblick auf die Performance des Programms.
andyritter
User
Beiträge: 29
Registriert: Montag 7. März 2016, 16:27

Vielen Dank für eure Erläuterungen,
ich habe mich dazu entschieden, die Datensätze direkt in die Datenbank zu schreiben ohne zuvor etwas zulöschen oder anzupassen.

for item in t['tenants']:
osp_tenants_tenant_id = item['id']
osp_tenants_name = item['name']
osp_tenants_description = item['description']
print(osp_tenants_tenant_id)
print(osp_tenants_name)
print(osp_tenants_description)
cur.execute("""INSERT INTO osp_tenants (name, tenant_id, description) VALUES (%s, %s, %s)""",(osp_tenants_name, osp_tenants_tenant_id, osp_tenants_description)

was mir hierbei noch nicht gelungen ist, ist die Prüfung der Tabelle mit IF EXISTS. das ist dann jedoch eine neuer Thread, oder?
Benutzeravatar
snafu
User
Beiträge: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Normalerweise ja, aber wir sehen das hier nicht ganz so eng. Solange das hier kein Sammelthread für deine Fragen der nächsten 12 Monate wird, denke ich, dass es in Ordnung geht, wenn du die Frage hier im Thread stellst.
andyritter
User
Beiträge: 29
Registriert: Montag 7. März 2016, 16:27

@snafu: ok, dann frage ich mal nach ;-)

Hier der Teil für den Insert erweitert um die Eingrenzung

Code: Alles auswählen

for item in t['tenants']:
    osp_tenants_tenant_id = item['id']
    osp_tenants_name = item['name']
    osp_tenants_description = item['description']
    print(osp_tenants_tenant_id)
    print(osp_tenants_name)
    print(osp_tenants_description)
    cur.execute("""INSERT INTO osp_tenants (name, tenant_id, description) VALUES (%s, %s, %s)""",(osp_tenants_name, osp_tenants_tenant_id, osp_tenants_description)\
"""(if not exists (select tenant_id from osp_tenants where tenant_id = %s)""",(osp_tenants_tenant_id))
    conn.commit()
erhalte ich immer Invalid Syntax und die Markierung steht auf dem letzten " vor
,(osp_tenants_tenant_id))
conn.commit()

Mein Ziel ist es, die Werte die in der Datenbank sind nicht nochmal einzufügen

ich hab schon so viel verschiedenes in Internet gelesen, aber einen besseren Ansatz habe ich noch nicht gefunden :cry:
Zuletzt geändert von Anonymous am Montag 21. März 2016, 17:32, insgesamt 1-mal geändert.
Grund: Quelltext in Code-Tags gesetzt.
BlackJack

@andyritter: Das ist halt kein gültiges Python. Und AFAIK wird das auch in SQL so nicht möglich sein mit einem bedingten Einfügen.

Entweder fragt man vorher die ID ab, oder man deklariert die als UNIQUE (falls das nicht sowieso schon der Primärschlüssel ist) und behandelt die auftretende Ausnahme entsprechend.
Benutzeravatar
miracle173
User
Beiträge: 127
Registriert: Samstag 6. Februar 2016, 00:28

@snafu: Wenn normalerweise ja, warum jetzt nicht? Es ist eigentlich nicht sinnvoll, eine andere Frage hier zu posten. Es passt nicht zum Thread-Titel, ist als Frage nicht zu finden und wenn jemand nocht etwas zur ursprünglichen Frage posten will, ergibt das dann ein völliges Durcheinander von Antworten. Einen Vorteil kann ich eigentlich keinen erkennen.
Benutzeravatar
snafu
User
Beiträge: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

@miracle173
Prinzipiell hast du Recht. Ich stimme deiner Begründung völlig zu.

Es ist aber jetzt auch kein Beinbruch für mich. Und ich weiß, dass auch in anderen Threads schon Folgefragen gestellt wurden, die zwar auf dem ursprünglichen Thema aufgebaut haben, aber streng genommen hätte man sie isoliert in einem eigenen Thread stellen müssen.

Wenn es dir ein wichtiges Anliegen ist, die beiden Themen zu trennen, dann wende dich am besten direkt an die Moderatoren (z.B an BlackJack), damit der Thread nachträglich gesplittet wird.

Wie gesagt: Mir ist es ehrlich gesagt egal, wenn man ausnahmsweise den selben Thread für eine Folgefrage nutzt. Es sollte nur nicht zur Regelmäßigkeit werden.
andyritter
User
Beiträge: 29
Registriert: Montag 7. März 2016, 16:27

@BlackJack: Ich habe die Spalte als UNIQUE deklariert. Danke für den Hinweis.


Ich habe den Insert wie folgt gelöst:

Code: Alles auswählen

# Einfügen der Werte aus der Tenant Abfrage
for item in t['tenants']:
    osp_tenants_tenant_id = item['id']
    osp_tenants_name = item['name']
    osp_tenants_description = item['description']
    #print(osp_tenants_tenant_id ,osp_tenants_name, osp_tenants_description)
    try:
        cur.execute("""INSERT INTO osp_tenants (name, tenant_id, description) VALUES (%s, %s, %s)""", (osp_tenants_name, osp_tenants_tenant_id, osp_tenants_description))
        print("Neuer Eintrag:", osp_tenants_name, osp_tenants_tenant_id, osp_tenants_description)
    except:
        print(osp_tenants_tenant_id,"schon vorhanden")
        print("-------------------------------------------------------")
Weitere Fragen werde ich in einem Neuen Thread stellen ;-)
Danke an alle für Eure Unterstützung. :D
Zuletzt geändert von Anonymous am Dienstag 22. März 2016, 11:55, insgesamt 1-mal geändert.
Grund: Quelltext in Code-Tags gesetzt.
BlackJack

@andyritter: Nackte ``except:``\s sind keine gute Idee. Du behandelst hier *jede* Ausnahme so als wäre die ID schon vorhanden, auch wenn die Ausnahme einen ganz anderen Grund hat. Zum Beispiel ein Programmierfehler, oder ein Netzwerkproblem, oder das die Datenbank nicht (mehr) erreichbar ist, oder…
andyritter
User
Beiträge: 29
Registriert: Montag 7. März 2016, 16:27

BlackJack hat geschrieben:@andyritter: Nackte ``except:``\s sind keine gute Idee. Du behandelst hier *jede* Ausnahme so als wäre die ID schon vorhanden, auch wenn die Ausnahme einen ganz anderen Grund hat. Zum Beispiel ein Programmierfehler, oder ein Netzwerkproblem, oder das die Datenbank nicht (mehr) erreichbar ist, oder…
@BlackJack: Wie kann ich denn einen IOError ausklammern, dass das Script weiter ausgeführt wird? Wenn ich den IOError mit aufführe,

Code: Alles auswählen

for item in t['tenants']:
    osp_tenants_tenant_id = item['id']
    osp_tenants_name = item['name']
    osp_tenants_description = item['description']
    #print(osp_tenants_tenant_id ,osp_tenants_name, osp_tenants_description)
    try:
        cur.execute("""INSERT INTO osp_tenants (name, tenant_id, description) VALUES (%s, %s, %s)""", (osp_tenants_name, osp_tenants_tenant_id, osp_tenants_description))
        print("Neuer Eintrag:", osp_tenants_name, osp_tenants_tenant_id, osp_tenants_description)
    except IOError as e:
        print(osp_tenants_tenant_id,"schon vorhanden")
        print("-------------------------------------------------------")
    else:
        print("alles ok")

erscheint diese Fehlermeldung:

Traceback (most recent call last):
File "/home/akquinet/Dokumente/Database_insert_tenants.py", line 76, in <module>
cur.execute("""INSERT INTO osp_tenants (name, tenant_id, description) VALUES (%s, %s, %s)""", (osp_tenants_name, osp_tenants_tenant_id, osp_tenants_description))
IntegrityError: duplicate key value violates unique constraint "osp_tenants_tenant_id_key"
DETAIL: Key (tenant_id)=(abcd) already exists.

Bei allen Möglichkeiten,die ich bei Google gefunden habe wird diese Fehlerbehandlung nicht dargestellt oder ich verstehe es nicht.
Zuletzt geändert von Anonymous am Donnerstag 24. März 2016, 09:59, insgesamt 1-mal geändert.
Grund: Quelltext in Code-Tags gesetzt.
BlackJack

@andyritter: Du behandelst einen `IOError` (warum?), und bekommst bei einer bereits vorhandenen `tenant_id` einen `IntegrityError`. Finde den Fehler. ;-)
andyritter
User
Beiträge: 29
Registriert: Montag 7. März 2016, 16:27

@BlackJAck: Wenn ich den IntegrityError abfangen will mit:

Code: Alles auswählen

for item in t['tenants']:
    osp_tenants_tenant_id = item['id']
    osp_tenants_name = item['name']
    osp_tenants_description = item['description']
    #print(osp_tenants_tenant_id ,osp_tenants_name, osp_tenants_description)
    try:
        cur.execute("""INSERT INTO osp_tenants (name, tenant_id, description) VALUES (%s, %s, %s)""", (osp_tenants_name, osp_tenants_tenant_id, osp_tenants_description))
        print("Neuer Eintrag:", osp_tenants_name, osp_tenants_tenant_id, osp_tenants_description)
    except IntegrityError as e:
        print(osp_tenants_tenant_id,"schon vorhanden")
        print("-------------------------------------------------------")
    else:
        print("alles ok")
Erhalte ich diese Fehlermeldung:

Traceback (most recent call last):
File "/home/akquinet/Dokumente/Database_insert_tenants.py", line 78, in <module>
except IntegrityError as e:
NameError: name 'IntegrityError' is not defined

Wobei mich dann wiederum stutzig macht, dass die Fehlerbezeichnung nicht definiert sein soll.
Zuletzt geändert von Anonymous am Donnerstag 24. März 2016, 10:23, insgesamt 1-mal geändert.
Grund: Quelltext in Code-Tags gesetzt.
Benutzeravatar
miracle173
User
Beiträge: 127
Registriert: Samstag 6. Februar 2016, 00:28

Code: Alles auswählen

Traceback (most recent call last):
File "/home/akquinet/Dokumente/Database_insert_tenants.py", line 76, in <module>
cur.execute("""INSERT INTO osp_tenants (name, tenant_id, description) VALUES (%s, %s, %s)""", (osp_tenants_name, osp_tenants_tenant_id, osp_tenants_description))
IntegrityError: duplicate key value violates unique constraint "osp_tenants_tenant_id_key"
DETAIL: Key (tenant_id)=(abcd) already exists.
Da braucht man nicht googeln, da braucht man schlimmstenfalls ein Lexikon, um sich das ganze ins Deutsche zu übersetzten, wenn man es so nicht versteht. Da steht doch alles drin, was passiert ist.

in etwa

Beim Ausführen von
cur.execute("""INSERT INTO osp_tenants (name, tenant_id, description) VALUES (%s, %s, %s)""", (osp_tenants_name, osp_tenants_tenant_id, osp_tenants_description))

Anmerkung von mir: das ist das Einfügen eines Datensatzes in die Datenbank

in der Zeile 76 der Datei "Database_insert_tenants.py" gabs den
Integritäts-Fehler: doppelter Schlüsselwert verletzt die Eindeutigkeitsbeschränkung "osp_tenants_tenant_id_key"
Detail: Den Schlüssel (tenant_id)=(abcd) gibt es schon.

Was ist dir daran nicht klar?
BlackJack

@andyritter: Das ist eine Ausnahme die spezifisch für Datenbanken ist, natürlich fällt das nicht einfach so vom Himmel und ist auf magische Weise verfügbar. Du musst die Ausnahme schon aus dem Modul importieren in dem sie definiert wurde, wie alle anderen Datentypen ausser den eingebauten halt auch.
andyritter
User
Beiträge: 29
Registriert: Montag 7. März 2016, 16:27

@miracle: Mir ist nicht klar, wie ich es fertig bringe, dass das Script weiterläuft, auch wenn für einen Datensatz ein "IntegrityError: duplicate key value violates unique constraint" geworfen wird.

@BlackJack: Leider habe ich keine Ahnung, in welchem Modul dieser Fehler definiert sein soll. Kannst Du mir da einen Tipp geben?
Danke schön
BlackJack

@andyritter: Nee, kann ich nicht. Ich bin gerade zu sehr mit kopfschütteln beschäftigt. In welchem Modul mag wohl der Ausnahmetyp für Datenbankfehler definiert sein… Wie soll man da bloss drauf kommen… :roll:
andyritter
User
Beiträge: 29
Registriert: Montag 7. März 2016, 16:27

except psycopg2.IntegrityError:
Antworten