Bearbeiten von Listen

Stellt hier eure Projekte vor.
Internetseiten, Skripte, und alles andere bzgl. Python.
Antworten
bas_oldy
User
Beiträge: 16
Registriert: Donnerstag 23. August 2018, 20:09

Hallo Python-Gemeinde,

beim Versuch mit Listen zu arbeiten habe ich folgendes Problem: Ich möchte eine Liste "ldf" von (5 * 5)-Feldern erstellen, in die nacheinander statt der vorhandenen Nullen andere Zahlen eingetragen werden, wobei die Plätze für die Zahlen und die einzutragenden Zahlen in einer eigenen Liste "ldz" stehen. Die Liste "ldf" sollte also nacheinander das Feld mit lauter Nullen, das Feld mit einer Zahl, das Feld mit zwei Zahlen usw. enthalten.

Mein Programm liefert aber eine Liste, in der alle Felder den den letzten Stand mit allen eingetragenen Zahlen haben. Kann mir jemand sagen, wo mein Fehler liegt?

Für Eure Hilfe herzlichen Dank.

Code: Alles auswählen

def bearbeite_feld(n):
    feld = ldf[n-1]
    x = ldz[0][0]
    y = ldz[0][1]
    z = ldz[0][2]
    feld[x][y] = z
    ldf.append(feld)
    del ldz[0]

ldf = [[[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0]]]

ldz = [[0,0,1],[4,2,2],[1,1,3],[1,0,4],[2,3,5],[3,2,6],[0,3,7],[4,4,8],[2,4,9]]

for k in range(1,10,1):
    bearbeite_feld(k)
   
for k in range(10):
    print()
    print("Feld_"+str(k)+":")
    for y in range(5):
        print(ldf[k][y])
Zuletzt geändert von __deets__ am Mittwoch 4. Dezember 2019, 18:55, insgesamt 1-mal geändert.
Grund: code tags gesetzt
Benutzeravatar
__blackjack__
User
Beiträge: 13080
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@bas_oldy: Naja, Du hängst halt immer das *selbe* Feld an und bearbeitest auch immer das *selbe* Feld, also hast Du am Ende 10× das *selbe* Feld. Der Indexzugriff oder `append()` entscheidet nicht einfach nicht das Objekt selbst sondern eine Kopie zu liefern oder anzuhängen, und dazu noch eine Tiefe Kopie, nur weil Du das an der Stelle praktisch finden würdest. Wenn Du eine Kopie willst, dann musst *Du* eine Kopie erstellen.

Da ist einiges was man so in Python nicht machen würde.

Zuerst einmal bekommen Funktionen und Methoden alles was sie ausser Konstanten benötigen als Argument(e) und greifen nicht auf irgendwelche globalen Variablen aus der Umgebung zu. `bearbeite_feld()` braucht also `ldf` und `ldz` als Argumente. Das sind übrigens verdammt schlechte Namen. Namen sollen dem Leser vermitteln was der Wert dahinter bedeutet.

Die Schleife über Indexwerte die bei 1 anfangen, und dann in der Funktion mit -1 wieder angepasst werden muss sollte gleich über die richtigen Werte laufen. Wobei das eigentlich gar nicht wirklich nötig ist, denn was Du da ja anscheinend machen willst ist immer auf das letzte Element von `ldf` zugerifen. Das geht mit dem Index -1, da braucht man kein `n` für.

Dann ist das herauslöschen des ersten Elements aus einer Liste in einer Funktion die diese Liste als Argument übergeben bekommt, absolut überraschend und komisch und schräg und ineffizient. Zudem muss das `range()` für die Schleife zur Länge von `ldz` passen. Fehleranfällig ist das neben der Undursichtigkeit auch noch. Was man hier eigentlich will ist eine Schleife über `ldz` und nicht ganz `ldz` an `bearbeite_feld()` übergeben, sondern immer nur das aktuelle Element von `ldz`, beziehungsweise beim iterieren über `ldz` schon die einzelnen Werte an Namen binden. Und dann sehe ich für das bisschen was da übrig bleibt auch keine Funktion mehr die *einen* Schritt der Schleife ausführt. Oder zumindest nicht in dieser Form.

Indexzugriffe in Schleifen sind in idiomatischem Python selten, weil man direkt über die Elemente von Sequenzen iterieren kann, ohne den Umweg über einen Index. Falls man *zusätzlich* eine laufende Zahl benötigt, gibt es die `enumerate()`-Funktion. Bei den beiden letzten Schleifen sind zudem wieder ”magische” Zahlen für die `range()`-Funktion die nur solange korrekt sind, solange man nichts an den Längen der betroffenen Listen ändern möchte.

Zeichenketten und Werte mit ``+`` und `str()` zusammenstückeln ist eher BASIC als Python. Python kennt dafür Zeichenkettenformatierung mit der `format()`-Methode auf Zeichenketten und ab Python 3.6 f-Zeichenkettenliterale.

Zwischenstand:

Code: Alles auswählen

#!/usr/bin/env python3
from copy import deepcopy


def main():
    ldz = [
        (0, 0, 1),
        (4, 2, 2),
        (1, 1, 3),
        (1, 0, 4),
        (2, 3, 5),
        (3, 2, 6),
        (0, 3, 7),
        (4, 4, 8),
        (2, 4, 9),
    ]
    ldf = [
        [
            [0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0],
        ]
    ]
    for x, y, z in ldz:
        feld = deepcopy(ldf[-1])
        feld[x][y] = z
        ldf.append(feld)

    for i, feld in enumerate(ldf):
        print()
        print(f"Feld_{i}:")
        for row in feld:
            print(row)


if __name__ == "__main__":
    main()
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
bas_oldy
User
Beiträge: 16
Registriert: Donnerstag 23. August 2018, 20:09

Hallo Blackjack,

vielen Dank für die ausführliche Besprechung und das viel bessere Programm. Ich werde alles aufmerksam durcharbeiten.
Dass etwa 40 Jahre Verwendung von BASIC Spuren hinterlässt, haben Sie ganz richtig bemerkt. Sorry!

mit freundlichen Grüßen
Benutzeravatar
__blackjack__
User
Beiträge: 13080
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Um mal Edsger Dijkstra zu zitieren: „It is practically impossible to teach good programming to students that have had a prior exposure to BASIC: as potential programmers they are mentally mutilated beyond hope of regeneration.“ 😉

Aber ich bin auch gerade wieder an BASIC dran. Während mein C64 an einer Lösung des heutigen Advent of Code-Rätsels mittels (kompiliertem) CBM BASIC V2 rechnete, habe ich das Programm auf einem DOS-Rechner in QBasic umgesetzt und in ca. 8 Minuten rechnen auf einem 486er festgestellt, dass der C64 sehr wahrscheinlich auch zu dem gleichen falschen Ergebnis kommen wird — was er dann nach 3½ Stunden auch tat. Was ich aber erst abends gesehen habe, weil der weiter gerechnet hat als ich zur Arbeit gefahren bin. Mittlerweile hat der heute Abend in weiteren 3½ Stunden auch das richtige Ergebnis ausgerechnet. 😀

Bin am überlegen ob ich das für den C64 noch mal in C und für den DOS-PC noch mal in Borland Pascal umsetze um zu schauen wie viel das schneller wird. Eine Idee für einen anderen Lösungsansatz hätte ich auch noch, aber morgen früh um sechs kommt ja bereits das nächste Rätsel.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Benutzeravatar
ThomasL
User
Beiträge: 1366
Registriert: Montag 14. Mai 2018, 14:44
Wohnort: Kreis Unna NRW

Ich hoffe nicht ganz so offtopic, aber wenn hier schon über BASIC gesprochen wird, falls es jemand noch nicht kennt:

The birth of BASIC https://www.youtube.com/watch?v=WYPNjSoDrqw

:!: :!: ABSOLUT SEHENSWERT :!: :!:
für Jung und Alt (so wie ich) :D
(BASIC auf Sinclair ZX80 1981 proud i am )
Ich bin Pazifist und greife niemanden an, auch nicht mit Worten.
Für alle meine Code Beispiele gilt: "There is always a better way."
https://projecteuler.net/profile/Brotherluii.png
Antworten