Seite 1 von 1

Vereinfachung arbeiten mit Listen

Verfasst: Dienstag 17. Oktober 2023, 20:29
von ereetzer
Hallo,

eine Frage an die Runde zum lernen für mich.
Zum weitern lernen habe ich eine kleines Programm mit Gui für den Gewichtsverlauf gebastelt. Unten ein Ausschnitt.
Ich habe den Eindruck das das ganze nicht besondern Python-konform ist. Ich denke irgendwie das ich das viel zu umständlich gemacht habe. Ich glaube ich bin da noch zu sehr im alten Delphi-Muster wo ich vor 15 Jahren ca. mal reingeschnuppert habe.
Geht das besser, kürzer und wenn ja wie? Also insbesondere der Bereich mit den Listen und dem auslesen daraus.

Codeausschnitt:

Code: Alles auswählen

	    def statistik_laden():
	    ...
	    ...
            sql_search = 'Select Datum, Gewicht from Gewicht where Gewicht = (select max(Gewicht) from Gewicht)'
            zeiger.execute(sql_search)
            fetch3 = zeiger.fetchall()
            jetzt = "now"
            siebentage = "-7 days"
            sql_search = f"select Datum, Gewicht from Gewicht where Datum > datetime('{jetzt}', '{siebentage}')"
            zeiger.execute(sql_search)
            fetch4 = zeiger.fetchall()
            # nur Gewichtswerte
            liste = []
            for werte in fetch4:    # alle Werte der letzten 7 Tage in eine Liste packen
                liste.append(werte[1])  # [1] = Gewicht, [0] wäre das Datum
            anzahl = len(liste)
            if anzahl < 2:  # wenn keine 2 Werte vorhanden sind, heißt das das in den letzten tagen maximal 1 Eintrag erzeugt wurde und damit kann kein Vergleich stattfinden
                liste = [0, 0]
            else:
                liste = [liste[0], liste[-1]]   # nur den letzten Wert und den ersten Wert in die Liste übernehmen
            print(liste)
            ergebnis = fetch + fetch1 + fetch2 + fetch3 + liste # alle Abfragen zusammenfügen
            print(ergebnis)
            zeiger.close()
            verbindung.commit()
            verbindung.close()
            return ergebnis
Auswerten tue ich das Ergebnis dann zum Beispiel so: (was irgendwie mit den nummern recht unübersichtlich ist

Code: Alles auswählen

            daten = statistik_laden()
            ...
            ...
            label_statistik_erster_wert.config(text=str(daten[2][0]) + " " + "(" + str(daten[2][1]) + ")")            
            label_statistik_letzter_wert.config(text=str(daten[3][0]) + " " + "(" + str(daten[3][1]) + ")")

Re: Vereinfachung arbeiten mit Listen

Verfasst: Dienstag 17. Oktober 2023, 21:30
von __blackjack__
@ereetzer: Als erstes solltest Du aufhören mit Tabs einzurücken, und dann auch noch mit Leerzeichen gemischt, denn die Einrückung sieht im Forum falsch aus, weil Du anscheinend bei Dir andere Werte für Tab verwendest als zumindest mein Browser. Per Konvention wird in Python vier echte Leerzeichen pro Ebene eingerückt.

Es ist ein bisschen komisch das die Funktion selbst auch eingerückt ist, als wäre die lokal in einer anderen Funktion definiert. Das macht man nicht, denn das lässt sich nur schlecht testen, und es wird unübersichtlich wenn dort dann vielleicht auch noch auch Namen aus umgebenden Sichtbarkeitsbereichen zugegriffen wird. Das passiert manchmal aus unabsichtlich und könnte damit ein Fehler sein.

`zeiger` für `cursor` finde ich komisch. Das ist ja nicht wirklich ein ”Zeiger”.

Die `close()`-Aufrufe bei Cursor und Verbindung würde ich mit einem ``finally`` absichern oder besser mit einem ``with`` und `contextlib.closing()`.

Der Rückgabewert ist in der Tat sehr eigenartig ”strukturiert”. Aber wir wissen ja auch gar nicht wie der insgesamt aussieht, weil da Werte fehlen. Das heisst was die Indexnummern in dem zweiten Beispiel bedeuten und auf welchen `fetch`-Teil da eigentlich zugegriffen wird, kann man überhaupt nicht sagen, mit dem was Du zeigst.

Namen nummerieren riecht schon komisch. Und `fetch` ist ja eher ein Kommando/eine Tätigkeit, ich verstehe nicht so ganz wie man das Ergebnis einer Datanbankabfrage so nennen kann.

Da `fetch3` keine feste Länge hat, muss man auf die Werte von `liste` (nicht nummeriert, aber als Name auch eher schlecht) nicht mit einem positiven Index zugreifen, sondern muss da von hinten kommen, mit -1 als Index.

Also das mit dem ``+`` der Teilergebnisse ist schon mal eine ganz schlechte Idee. In einer Liste sollten alle Elemente die gleiche Bedeutung haben. Wenn man dann auch noch Listen mit unterschiedlicher Bedeutung *und* variablen Längen in *eine* *flache* Liste steckt, dann wird es umständlich bis unmöglich das wieder auseinander zu pflücken.

Feste Werte in Zeichenketten einsetzen macht es nicht wirklich übersichtlicher.

Warum werden die Datumsangaben bei `fetch4` abgefragt wenn der Code die dann weg wirft?

Man muss nicht jedes kleine Zwischenergebnis an einen Namen binden.

Zwischenstand (ungetestet):

Code: Alles auswählen

from contextlib import closing


def statistik_laden():
    ...
    with closing(...) as verbindung:
        with closing(verbindung.cursor()) as zeiger:
            zeiger.execute(
                "SELECT datum, gewicht"
                " FROM gewicht"
                " WHERE gewicht = (SELECT max(gewicht) FROM gewicht)"
            )
            maximalgewichte = zeiger.fetchall()

            zeiger.execute(
                "SELECT gewicht"
                " FROM gewicht"
                " WHERE datum > datetime('now', '-7 days')"
            )
            gewichte_der_letzten_sieben_tage = [
                row[0] for row in zeiger.fetchall()
            ]
            gewichte = (
                (0, 0)
                if len(gewichte_der_letzten_sieben_tage) < 2
                else (
                    gewichte_der_letzten_sieben_tage[0],
                    gewichte_der_letzten_sieben_tage[-1],
                )
            )

            verbindung.commit()

            return (fetch, fetch1, fetch2, maximalgewichte, gewichte)
Und mindestens das zurückgegebene Tupel sollte kein Tupel sein, sondern mindestens ein `collections.namedtuple` oder eine Klasse mit sinnvollen Attributnamen statt magischer Indexwerte.

Der Code der das dann benutzt sollte Zeichenkettenformatierung verwenden und nicht Zeichenketten und Werte mit `str()` und ``+`` zusammenstückeln. Ist ja kein BASIC, sondern Python. f-Zeichenkettenliterale kennst Du doch bereits.

Re: Vereinfachung arbeiten mit Listen

Verfasst: Mittwoch 18. Oktober 2023, 17:18
von Sirius3
Beim zweiten `select` fehlt noch ein `order by datum` wenn man nicht zwei beliebige Werte des Gewichts haben möchte.