Funktion schreibt nicht in Liste

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
optido
User
Beiträge: 4
Registriert: Montag 31. Oktober 2022, 13:49

Hallo zusammen,

ich habe folgendes Problem:

Ich lege eine leere Liste rel_sterblichkeit an.
Im weiteren Programmablauf wird die Funktion rechnung() aufgerufen. Diese soll über alle Zeilen und Spalten von daten_mort laufen und die Rechenergebnisse für alle Zeilen in die Liste rel_sterblichkeit schreiben.
Für die erste Zeile passiert dies und danach wird nichts mehr gefüllt. Was ich noch nachvollziehen kann, ist, daß i hochgezählt wird.

Über einen Hinweis würde ich mich freuen.
Gruß
Stefan


Code: Alles auswählen


rel_sterblichkeit = []
anz_spalten = 509
anz_zeilen = 41

def rechnung():
    global rel_sterblichkeit
    rel_sterblichkeit=[[0 for j in range(anz_spalten)] for i in range(anz_zeilen)]
    i=0
    j=9
   
    while i < anz_zeilen:
        k=0
        print(i)
        print(j)
        while j<=anz_spalten-8:
            rel_sterblichkeit[i][k]=daten_mort[i][j+1]/(daten_mort[i][j+2]-daten_mort[i][j+1]+daten_mort[i][j+3])
            j=j+5
            k=k+1
    
        i=i+1
   
    return rel_sterblichkeit;

Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@optido: Was Du gleich anders machen solltest bevor überhaupt dran zu denken ist da Fehler zu finden ist ``global`` loszuwerden. Auf Modulebene sollte nur Code stehen der Konstanten, Funktionen, und Klassen definiert. Das Hauptprogramm steht üblicherweise in einer Funktion die `main()` heisst.

Man verwendet keine globalen Variablen. Alles was Funktionen und Methoden ausser Konstanten verwenden, bekommen sie als Argument(e) übergeben. Und Ergebnisse werden nicht in globale Variablen geschrieben, sondern als Rückgabewert an den Aufrufer zurückgegeben. Das macht die Funktion ja sogar, und sie erstellt auch die Liste selbst, also macht das überhaupt auch gar keinen Sinn hier ``global`` *und* einen Rückgabewert zu verwenden.

Konstanten werden in Python per Konvention KOMPLETT_GROSS geschrieben. Also sofern `anz_spalten` und `anz_zeilen` nicht auch besser Argumente sein sollten, sollte man die Namen entsprechend anpassen.

Namen sollten keine kryptischen Abkürzungen enthalten, und sofern man nicht Yoda heisst, sollte man Worte in Namen ”normal” anordnen. `ANZ_SPALTEN` wäre beispielsweise `SPALTENANZAHL`.

Die Ergebnisliste lässt sich etwas einfacher initialisieren wenn man die innere „list comprehension“ durch ``[0] * ANZ_SPALTEN`` ersetzt.

Für Namen die man aus syntaktischen Gründen braucht, deren Wert aber gar nicht verwendet wird, gibt es die Konvention die einfach `_` zu nennen. Dann weiss der Leser gleich das der Wert keine Rolle spielt, und muss nicht schauen ob es ein Fehler ist, das der gar nicht verwendet wird, oder ob der Code noch nicht ganz fertig programmiert ist.

*Beide* ``while``-Schleifen sind (wahrscheinlich) eigentlich ``for``-Schleifen. Bei der inneren ist das nicht so ganz klar, denn hier scheinst Du den Fehler gemacht zu haben: `j` sollte eventuell wieder auf einen kleineren Wert zurückgesetzt werden? Denn wenn die innere ``while``-Schleife einmal durchgelaufen ist, sehe ich nicht wie die noch mal durchlaufen werden kann.

Ich vermute einfach mal das `j` jedes mal auf 9 gesetzt werden soll bevor die Schleife läuft und nicht nur einmal vor der äusseren Schleife.

Und ich unterstelle auch mal das die `daten_mort` Datenstruktur so gross ist, dass `k` hier alle Werte von 0 bis SPALTENANZAHL-1 annehmen wird. Womit `k` überflüssig wird. Denn eine Datenstruktur mit Dummywerten anzulegen und danach dann jeden Dummywert der Reihe nach durch den tatsächlichen Wert zu ersetzen ist etwas was man in Python nicht macht. Man baut die Datenstruktur gleich mit den richtigen Werten auf. Damit braucht man `k` nicht mehr.

Überhaupt sind Indexzugriffe in Python fast ein „code smell“ weil die reltiv selten vorkommen. `i` braucht man nämlich auch nicht, denn das wird nur dazu benutzt um der Reihe nach auf Sequenzen zuzugreifen. Man kann in Python aber direkt über die Elemente von Sequenzen iterieren, ohne den unnötigen Umweg über einen Laufindex.

Bei dem ``return`` ist am Ende ein überflüssiges Semikolon. Die braucht man in Python eigentlich fast nie, weil die keine Anweisungen abschliessen, wie in einigen anderen Programmiersprachen, sondern mehrere Anweisungen in einer Zeile trennen. Da man aber nur eine Anweisung pro Zeile schreiben sollte, braucht man das nicht.

Kleiner Zwischenstand:

Code: Alles auswählen

def rechnung(mortalitaetsmatrix):
    relative_sterblichkeitsmatrix = []

    for mortalitaets_zeile in mortalitaetsmatrix:
        ergebniszeile = []
        for j in range(9, SPALTENANZAHL - 9, 5):
            ergebniszeile.append(
                mortalitaets_zeile[j + 1]
                / (
                    mortalitaets_zeile[j + 2]
                    - mortalitaets_zeile[j + 1]
                    + mortalitaets_zeile[j + 3]
                )
            )
        relative_sterblichkeitsmatrix.append(ergebniszeile)

    return relative_sterblichkeitsmatrix
Die Schleifenkörper sind jetzt so simpel, dass man aus beiden Schleifen „list comprehensions“ machen kann.

Code: Alles auswählen

def rechnung(mortalitaetsmatrix):
    return [
        [
            mortalitaets_zeile[j + 1]
            / (
                mortalitaets_zeile[j + 2]
                - mortalitaets_zeile[j + 1]
                + mortalitaets_zeile[j + 3]
            )
            for j in range(9, SPALTENANZAHL - 9, 5)
        ]
        for mortalitaets_zeile in mortalitaetsmatrix
    ]
Wobei das mit dem `j` ziemlich sicher noch nicht richtig ist. Aber so in der Richtung sollte das in Python am Ende aussehen, statt da mit Indexwerten zu hantieren.

Was da mit `j` gemacht wird sieht auch irgednwie komisch aus. Kann es sein, dass in den Eingabedaten Listen sind bei denen jeweils 5 aufeinanderfolgende Werte zusammengehören und jeder dieser Werte ein andere Bedeutung hat‽ Das sollte so nicht sein. Elemente in einer Liste sollten alle die gleiche Bedeutung haben. Wenn meine Vermutung stimmt, sollten jeweils 5 Werte zu *einem* Wert zusammengefasst werden. Mindestens ein Tupel, bei der Anzahl der zusammengefassten Werte besser ein `collections.namedtuple()`, damit man nicht mit magischen Indexwerten, sondern mit verständlichen Namen auf die Bestandteile zugreifen kann.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
optido
User
Beiträge: 4
Registriert: Montag 31. Oktober 2022, 13:49

Herzlichen Dank!
Das bringt mich wirklich weiter.
Antworten