Liste an Liste anhängen

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
PyFlo
User
Beiträge: 9
Registriert: Montag 21. Februar 2022, 14:11

Hallo zusammen,

ich möchte mir selbst das Programmieren mit Python mittels Tutorials & Lehrbuch beibringen.
Dafür überlege ich mir immer kleine Programmieraufgaben, damit ich das gelernte direkt umsetzen kann. Allerdings bin ich nun auf ein Verständnisproblem gestoßen, bzw. bekomme nicht die gewünschte Ausgabe.

Die Programmieraufgabe:
Ich möchte mittels for-Schleife eine Datenabfrage von Personen machen und diese Daten in einer Liste speichern. Dafür soll eine Personenliste erstellt werden, in der die Daten als Liste gespeichert werden.

Code: Alles auswählen

list_Pers = [[Daten_Pers1], [Daten_Pers2], ...]
Hierfür habe ich folgenden Code geschrieben:

Code: Alles auswählen

anzahlPers = int(input("Wie viele Personen möchten Sie befragen? "))

list_Pers = [None for x in range(anzahlPers)]
# list_Pers = []

daten_Pers = ["Vorname", "Nachname", "Alter"]

for anzahl in range(anzahlPers):
    print("--- Daten für Person ", anzahl+1, " ---")
    daten_Pers[0] = str(input("Geben Sie ihren Vornamen ein: "))
    daten_Pers[1] = str(input("Geben Sie ihren Nachnamen ein: "))
    daten_Pers[2] = int(input("Geben Sie ihr Alter ein: "))
    print(daten_Pers)
    list_Pers[anzahl] = daten_Pers
    # list_Pers.append((daten_Pers))
    print(list_Pers)

print("ENDE")
Zu meinem Problem:
Wenn ich die Datenabfrage für zwei oder mehrere Personen durchführe (mehrere Durchgänge der for-Schleife), bestehen die Einträge der Personenliste nur aus den Daten des letzten Schleifendurchgangs anstatt jedes einzelnen Durchgangs.
Ausgabe der Personenliste:

Code: Alles auswählen

 [['Person2', 'Name2', 20], ['Person2', 'Name2', 20]] 
Ich habe schon mehrere Lösungen ausprobiert (s. kommentierte Zeilen im Code), allerdings führen sie nie zum gewünschten Ergebnis.

Es wäre super, wenn mir jemand weiterhelfen könnte.
Schon einmal vielen Dank im Vorraus! :)
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Du machst hier einen kategorischen Fehler: auch wenn es moeglich ist, und manchmal auch gemacht wird, ist es nahezu immer ein Fehler, eine Liste in-place zu modifizieren. Und den begehst du gleich zweimal:

1) Durch Anlage einer prae-alloziertet Liste. Abgesehen davon, dass die Benutzerfuehrung hier hakelig ist - statt vorher abzufragen, wieviele Personen man eingeben will, ist es deutlich leichter zu benutzen, wenn man einfach eine neue Person eingibt, oder "abbruch" oder eine leere Eingabe zum beenden nutzt - ist das viel zu kompliziert. Einfach eine neue Person anhaengen.
2) daten_pers ist ebenfalls immer die gleiche Liste, und hier liegt auch der Kern deines Problems: du modifizierst immer die gleiche Liste, und in der Liste drumrum fuegst du einfach nur X Referenzen auf die gleiche Liste ein. Stattdessen wuerde man hier aus den drei Eingaben einfach ein *neues* Tupel bauen, und das anhaengen. Und man benutzt ein Tupel, wenn man nicht-homogene Daten hat, die eigentlich eine Datenstruktur sind. Keine Listen. Die sind fuer gleichartige Dinge, also zB Personen. Aber nicht fuer Namen, Nachnamen, Alter, Haustier, etc...
PyFlo
User
Beiträge: 9
Registriert: Montag 21. Februar 2022, 14:11

Okay, vielen Dank für die schnellen Hinweise und Hilfestellung!
zu Punkt 1: Das mit dem Abbruchkriterium muss ich mir erst einmal genauer anschauen. So weit bin ich leider noch nicht mit dem Programmieren. :D
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Na einfach pruefen, ob die Eingabe leer war. Das ist nicht schwer. Und dann die Schleifenart wechseln, von for zu while.
Sirius3
User
Beiträge: 18279
Registriert: Sonntag 21. Oktober 2012, 17:20

Variablennamen schreibt man nach Konvention komplett klein. Benutze keine Abkürzungen, das macht das Lesen nur unnötig schwer anzahlPers -> anzahl_personen, list_Pers -> personen.
Man modifiziert keine Liste sondern erzeugt bei Bedarf neue Listen. Du hast ja schon `append` auskommentiert.
`input` liefert schon einen String, den nochmals per `str` umzuwandeln ist unnötig.
Wenn man über eine Anzahl eine for-Schleife hat, dann ist der einzelne Durchgang keine `anzahl`, sondern ein Index, oder eine Nummer.
Statt immer +1 draufzuzählen, sollte die for-Schleife schon die richtigen Werte liefern. Benutzt Format-Strings.

Code: Alles auswählen

anzahl_personen = int(input("Wie viele Personen möchten Sie befragen? "))

personen = []
for nummer in range(1, anzahl_personen + 1):
    print(f"--- Daten für Person {nummer} ---")
    vorname = input("Geben Sie ihren Vornamen ein: ")
    nachname = input("Geben Sie ihren Nachnamen ein: ")
    alter = int(input("Geben Sie ihr Alter ein: "))
    personen.append((vorname, nachname, alter))
    print(personen)
PyFlo
User
Beiträge: 9
Registriert: Montag 21. Februar 2022, 14:11

@Sirius3: auch an dich vielen Dank!
Die Konventionen kenne ich leider als Programmieranfänger noch nicht (sind in meinem Lehrbuch leider nicht beschrieben), aber es ist sicherlich gut sie so früh wie möglich kennenzulernen.
Auch die String-Formatierung kannte ich bisher noch nicht, ist aber sehr hilfreich.

Und morgen werde ich den Vorschlag von @__deets__ mit einer while-Schleife versuchen umzusetzen. Für eine vorher nicht festgelegte Anzahl an Personen ist das natürlich besser.
PyFlo
User
Beiträge: 9
Registriert: Montag 21. Februar 2022, 14:11

Hallo ich bin es nochmals :)
Ich habe jetzt doch noch den Vorschlag mit der while-Schleife umgesetzt.

Code: Alles auswählen

# Initialisierung
x = 1
personen = []

# Datenabfrage & Speichern in Liste
while True:
    print(f"--- Daten für Person {x} ---")
    vorname = input("Vorname: ")
    if vorname == "":                       # Abbruchkriterium für leere Eingabe
        break
    nachname = input("Nachname: ")
    alter = int(input("Alter: "))

    personen.append((vorname, nachname, alter))
    print(personen)
    x += 1

print(personen)
print("ENDE")
Dazu habe ich noch eine Frage: Das Abbruchkriterium für die while-Schleife habe ich mittels "Enter"-Eingabe umgesetzt. Gibt es hierfür noch eine bessere Lösung, oder kann man das so machen?
Sirius3
User
Beiträge: 18279
Registriert: Sonntag 21. Oktober 2012, 17:20

"Enter" ist doch schon eine sehr einfache Lösung zum Abbruch.
`x` ist ein schlechter Name für einen Index. Statt händisch eine Variable hochzuzählen, benutzt man statt dessen eine for-Schleife.

Code: Alles auswählen

from itertools import count

personen = []
for nummer in count(1):
    print(f"--- Daten für Person {nummer} ---")
    vorname = input("Vorname: ")
    if vorname == "":
        # Abbruchkriterium für leere Eingabe
        break
    nachname = input("Nachname: ")
    alter = int(input("Alter: "))

    personen.append((vorname, nachname, alter))
print(personen)
Benutzeravatar
__blackjack__
User
Beiträge: 14078
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Alternativ kann man `x`/`nummer` auch ganz weg lassen, denn das was da ausgegeben werden soll ist ja immer ``len(personen) + 1``. Die Liste kennt ja ihre eigene Länge und man kann die effizient abfragen und sich somit eine zusätzliche Variable sparen.
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
PyFlo
User
Beiträge: 9
Registriert: Montag 21. Februar 2022, 14:11

Vielen Dank für die weiteren Tipps & Hinweise!
Ich finde es übrigens super, dass in diesem Forum Fragen so schnell beantwortet werden und auch vermeintlich einfache Fragen Programmieranfängern erklärt werden. :)

Zur Funktion itertools.count() habe ich allerdings eine weitere Frage. Diese macht laut Dokumentation

Code: Alles auswählen

def count(start=0, step=1):
    # count(10) --> 10 11 12 13 14 ...
    # count(2.5, 0.5) -> 2.5 3.0 3.5 ...
    n = start
    while True:
        yield n
        n += step
ja nichts anderes, als ich in meiner while-Schleife. Es wird ein Counter nach jedem Schleifendurchgang erhöht. Dadurch wird das Programm ja vermutlich nicht schneller durchlaufen, als in meiner Lösung.
Ist es dann eine Programmier-Konvention die Iteration möglichst mit der itertools-Bibliothek umzusetzen, oder wird es dem entsprechenden Programmierer überlassen?
Sirius3
User
Beiträge: 18279
Registriert: Sonntag 21. Oktober 2012, 17:20

Es geht nicht um Geschwindigkeit, denn dann ist man in Python an der falschen Stelle. Es geht um Lesbarkeit. Und bei einer while-Schleife muß man verstehen, was dieses `x` bedeutet, das vor der Schleife auf 0 gesetzt wird, und innerhalb der Schleife irgendwo mit einer Mathematischen Operation verändert wird. Bei einem Counter ist es klar, dass der einfach nur zählt.
PyFlo
User
Beiträge: 9
Registriert: Montag 21. Februar 2022, 14:11

Sirius3 hat geschrieben: Dienstag 22. Februar 2022, 14:18 Es geht nicht um Geschwindigkeit, denn dann ist man in Python an der falschen Stelle. Es geht um Lesbarkeit. Und bei einer while-Schleife muß man verstehen, was dieses `x` bedeutet, das vor der Schleife auf 0 gesetzt wird, und innerhalb der Schleife irgendwo mit einer Mathematischen Operation verändert wird. Bei einem Counter ist es klar, dass der einfach nur zählt.
Okay, vielen Dank! :)
Antworten