Dictionary-Einträge in Zufallsreihenfolge

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.
lordzwieback
User
Beiträge: 55
Registriert: Montag 2. März 2015, 14:35
Kontaktdaten:

Guten Tag und Hallo liebe Community,

erster Beitrag, erstes Problem.. ;)

Folgendes: Ich habe mir als erstes kleines Programm eine Lernhilfe fürs OSI-Modell überlegt. In einem Dictionary lege ich die Keys und Values an (siehe Code weiter unten). Danach gebe ich in einer for-Schleife die Keys aus und frage die jeweiligen Values ab. Sind diese richtig beantwortet, wird zum nächsten Key gesprungen, falls nicht, wird die korrekte Antwort noch angezeigt.

Soweit klappt das auch. Doch zwei Sachen stören mich.

- Da ich nicht möchte, dass er nach 7 Abfragen das Programm verlässt, habe ich eine While Schleife eingebaut, jedoch verstehe ich nicht ganz, wieso er bei der Eingabe von "x" nicht aus der Schleife springt

- Momentan ist die Reihenfolge zwar "durcheinander", aber nicht zufällig. Beispiel: 3, 1, 5, 4, 7, 6, 2, 3, 1, 5, 4, 7, 6, 2, 3, 1, 5, 4, 7, 6, 2 usw... soll heißen das Muster wiederholt sich andauernd. Ich hätte aber gern, dass die Keys zufällig sind. Ist das irgendwie zu bewerkstelligen ?

Hier noch mein Code:

Code: Alles auswählen

schicht = {"Schicht 1": "Bitübertragungsschicht", "Schicht 2": "Sicherungsschicht", "Schicht 3": "Vermittlungsschicht",
           "Schicht 4": "Transportschicht", "Schicht 5": "Sitzungsschicht", "Schicht 6": "Darstellungsschicht",
           "Schicht 7": "Anwendungsschicht"}

lWeiter = True

while lWeiter:
    for q, a in schicht.items():
        print(q + ": ")
        antwort = input()
        if antwort == a:
            print("Richtige Antwort")
        elif antwort != a:
            print("Falsch, richtig wäre " + a)
        elif antwort == "x":
            lWeiter = False
            break
Danke schonmal im Voraus fürs Lesen und Helfen.

Grüße,
lordzwieback
BlackJack

@lordzwieback: Beschreib doch mal den Programmablauf nach der Eingabe von 'x'. Warum denkst Du dass die Schleife dadurch beendet werden sollte? Wann wird der letzte ``elif``-Zweig ausgeführt? Wann kommt es überhaupt dazu das die Bedingung dort geprüft wird?

Im `random`-Modul findest Du eine Funktion um Elemente in einer Liste zufällig zu mischen.
lordzwieback
User
Beiträge: 55
Registriert: Montag 2. März 2015, 14:35
Kontaktdaten:

BlackJack hat geschrieben:@lordzwieback: Beschreib doch mal den Programmablauf nach der Eingabe von 'x'. Warum denkst Du dass die Schleife dadurch beendet werden sollte? Wann wird der letzte ``elif``-Zweig ausgeführt? Wann kommt es überhaupt dazu das die Bedingung dort geprüft wird?
Nach der Eingabe von "x" soll das Programm in den 2. elif-Zweig springen, aus der while-Schleife gehen und somit den Programmablauf beenden.
So wie es momentan ausschaut, springt er nie in den letzten elif, was ich nicht verstehe. In den ersten beiden Fällen prüft er die Variable "antwort" immer korrekt. Warum er die Eingabe von "x" nicht erkennt, weiß ich nicht.

Das mit dem random Modul werde ich mir mal anschauen, danke.
Sirius3
User
Beiträge: 18260
Registriert: Sonntag 21. Oktober 2012, 17:20

@lordzwieback: wann ist das erste if wahr und wann das zweite?
lordzwieback
User
Beiträge: 55
Registriert: Montag 2. März 2015, 14:35
Kontaktdaten:

Sirius3 hat geschrieben:@lordzwieback: wann ist das erste if wahr und wann das zweite?
Das erste if ist wahr, wenn die eingegebene Antwort (input) dem Value des angezeigten Keys entspricht.

Das zweite if tritt ein, wenn die eingegebene Antwort (input) nicht dem Value des angezeigten Keys entspricht.

In der For-Schleife entspricht q (question) dem Key und a (answer) dem Value.

Beispiel:
q = "Schicht 2", a = "Sicherungsschicht", antwort = "Darstellungsschicht -> Falsche Antwort
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Du solltest ganz dringend auch an Deinen Namen arbeiten... ``q``, ``a`` und auch ``lWeiter`` sind schlecht. Wieso nicht ``question`` und ``answer``? Wieso mischst Du Deutsch und Englisch? (Am besten nur Englische Bezeichner verwenden!) Was soll das kleine ``l`` vor ``Weiter``? Laut PEP8 - dem Stylguide für Python - sollte man für Bezeichner auch kein mixedCase verwenden, sondern names_with_underscores nutzen.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
BlackJack

@lordzwieback: Und welchen Wert müsste `antwort` haben damit weder die erste noch die zweite Bedingung zutrifft? Denn nur in dem Fall kommt es ja überhaupt nur dazu das die dritte Bedingung geprüft wird.
lordzwieback
User
Beiträge: 55
Registriert: Montag 2. März 2015, 14:35
Kontaktdaten:

Hyperion hat geschrieben:Du solltest ganz dringend auch an Deinen Namen arbeiten... ``q``, ``a`` und auch ``lWeiter`` sind schlecht. Wieso nicht ``question`` und ``answer``? Wieso mischst Du Deutsch und Englisch? (Am besten nur Englische Bezeichner verwenden!) Was soll das kleine ``l`` vor ``Weiter``? Laut PEP8 - dem Stylguide für Python - sollte man für Bezeichner auch kein mixedCase verwenden, sondern names_with_underscores nutzen.
Ich hab irgendwann mal gelernt dass ich die Datentypen vor die Variablen zu schreiben wie z.B. cChar, iInt, lLogic.. aber is ok, ich habs kapiert.
BlackJack hat geschrieben:@lordzwieback: Und welchen Wert müsste `antwort` haben damit weder die erste noch die zweite Bedingung zutrifft? Denn nur in dem Fall kommt es ja überhaupt nur dazu das die dritte Bedingung geprüft wird.
Die Variable "antwort" müsste den Buchstaben "x" enthalten. Wenn ich den Buchstaben "x" als Antwort eingebe, sollte er in diesen elif-Zweig springen.

Falls ich was komplett falsch verstehe bitte ich das zu entschuldigen, ich bin noch nicht so lange dabei..
Sirius3
User
Beiträge: 18260
Registriert: Sonntag 21. Oktober 2012, 17:20

@lordzwieback: bei einer elif-Kette wird der erste Block, der die Bedingung erfüllt durchlaufen, und zwar nur der. Mehr kann man da nicht sagen, ohne Dir die Antwort zu verraten, was dann den Lerneffekt zunichte machen würde.
lordzwieback
User
Beiträge: 55
Registriert: Montag 2. März 2015, 14:35
Kontaktdaten:

Sirius3 hat geschrieben:@lordzwieback: bei einer elif-Kette wird der erste Block, der die Bedingung erfüllt durchlaufen, und zwar nur der. Mehr kann man da nicht sagen, ohne Dir die Antwort zu verraten, was dann den Lerneffekt zunichte machen würde.
Ah, das wusste ich nicht, danke für die Info. Werd mich da mal schlau machen.

EDIT: Danke, dein Hinweis hat mir weitergeholfen.

Habe nun einen elif-Zweig, welcher prüft, ob der Antwortstring ungleich dem Value des Keys ist. Falls dieser Fall eintrifft wird zuerst geprüft, ob der falsche String ein x ist (if antwort == "x"). In diesem if beende ich dann die Ausführung des Programms, das klappt.

Code: Alles auswählen

elif guess != answer:
    if guess == "x":
        continue_program = False
        break
    print("Falsch, richtig wäre " + answer)
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

lordzwieback hat geschrieben: Ich hab irgendwann mal gelernt dass ich die Datentypen vor die Variablen zu schreiben wie z.B. cChar, iInt, lLogic.. aber is ok, ich habs kapiert.
Das ist die "pervertierte" ungarische Notation. Zum einen war das damals vom Erfinder anders gedacht als später von vielen interpretiert und umgesetzt, zum anderen birgt dies einfach zu viel Fehlerpotenzial, bringt kaum Informationsgewinn ("objA"... Aha vom Typ ``object`` :mrgreen: ) dafür aber viel Overhead.

In Python geht es ohnehin - trotz starker Typisierung, bei Python also zur Laufzeit klarer Entscheidbarkeit, welchen Typ ein Objekt besitzt - eher um gleichartiges Verhalten ("Duck Typing"), als um Typeinschränkungen für Variablen. Viele Funktionen lassen sich mit exterm unterschiedlichen Typen aufrufen, weil sie von denen nur eine spezielle Funktionalität nutzen. Wie würde man so einen Parameter dann benennen? Schwierig, weil man ja kaum schreiben will ``listeodertupeloderdictionaryoderstringVar`` ;-)

Versuche also in einem Namen zu beschreiben, was sich dahinter verbirgt. ``question`` oder ``answer`` für eine Antwort ist in Deinem Kontext durchaus klarer, als ein simples ``q`` oder ``a``. Kollidiert das mit der vom Benutzer eingegeben Antwort, so kann man den Namen für Antworten ggf. ergänzen z.B. ``correct_answer`` und ``gussed_answer`` o.ä. Dabei ist nicht wichtig, dass es sich (aktuell) dabei um einen String handelt.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
lordzwieback
User
Beiträge: 55
Registriert: Montag 2. März 2015, 14:35
Kontaktdaten:

Hyperion hat geschrieben:
lordzwieback hat geschrieben: Ich hab irgendwann mal gelernt dass ich die Datentypen vor die Variablen zu schreiben wie z.B. cChar, iInt, lLogic.. aber is ok, ich habs kapiert.
Das ist die "pervertierte" ungarische Notation. Zum einen war das damals vom Erfinder anders gedacht als später von vielen interpretiert und umgesetzt, zum anderen birgt dies einfach zu viel Fehlerpotenzial, bringt kaum Informationsgewinn ("objA"... Aha vom Typ ``object`` :mrgreen: ) dafür aber viel Overhead.

In Python geht es ohnehin - trotz starker Typisierung, bei Python also zur Laufzeit klarer Entscheidbarkeit, welchen Typ ein Objekt besitzt - eher um gleichartiges Verhalten ("Duck Typing"), als um Typeinschränkungen für Variablen. Viele Funktionen lassen sich mit exterm unterschiedlichen Typen aufrufen, weil sie von denen nur eine spezielle Funktionalität nutzen. Wie würde man so einen Parameter dann benennen? Schwierig, weil man ja kaum schreiben will ``listeodertupeloderdictionaryoderstringVar`` ;-)

Versuche also in einem Namen zu beschreiben, was sich dahinter verbirgt. ``question`` oder ``answer`` für eine Antwort ist in Deinem Kontext durchaus klarer, als ein simples ``q`` oder ``a``. Kollidiert das mit der vom Benutzer eingegeben Antwort, so kann man den Namen für Antworten ggf. ergänzen z.B. ``correct_answer`` und ``gussed_answer`` o.ä. Dabei ist nicht wichtig, dass es sich (aktuell) dabei um einen String handelt.
Danke für die Tipps, werde mir die PEP8 Codierungsregeln mal genauer anschauen. ;)
lordzwieback
User
Beiträge: 55
Registriert: Montag 2. März 2015, 14:35
Kontaktdaten:

Nochmal zum ursprünglichen Problem, der Zufallsauswahl von Keys des Dictionarys:

Habe mich über das "random"-Modul informiert und herausgefunden, dass ich die Keys zuerst in eine Liste umwandeln muss, in etwa so:

Code: Alles auswählen

random.choice(list(osi_model.keys()))
Hier sollte eine Liste mit Keys angelegt werden und ein zufälliger Key ausgewählt werden (soweit ich das verstanden habe).
Da bei jedem Durchlauf ein zufälliger Key ausgewählt werden soll, muss ich diesen Befehl in die for-Schleife einbauen (falls das falsch sein sollte, verbessert mich bitte).

Hier nochmal mein kompletter Code zur Zeit:

Code: Alles auswählen

import random

osi_model = {"Schicht 1": "Bitübertragungsschicht", "Schicht 2": "Sicherungsschicht","Schicht 3": "Vermittlungsschicht",
             "Schicht 4": "Transportschicht", "Schicht 5": "Sitzungsschicht", "Schicht 6": "Darstellungsschicht",
             "Schicht 7": "Anwendungsschicht"}

continue_program = True
while continue_program:
    for question, answer in osi_model.items():
        random.choice(list(osi_model.keys()))
        print(question + ": ")
        guessed_answer = input()
        if guessed_answer == answer:
            print("Richtige Antwort")
        elif guessed_answer != answer:
            if guessed_answer == "x":
                continue_program = False
                break
            print("Falsche Antwort, richtig wäre " + answer)

Problem ist immer noch, dass er die Schichten zwar durcheinander anzeigt, aber immer im selben Muster (wie oben schon beschrieben). Eventuell kann mir ja nochmal jemand einen Hinweis geben, der mir weiterhilft.

Freue mich auf eure Antworten. ;)

Grüße,
lordzwieback
BlackJack

@lordzwieback: `random.choice()` wählt ein zufälliges Element aus und gibt das zurück. Du machst mit diesem Rückgabewert dann aber gar nichts wodurch die Zeile absolut gar keinen Effekt auf den Rest des Programms hat.

Es ist auch nicht die Funktion die eine Liste zufällig mischt. Denn selbst wenn Du mit `choice()` bei jedem Durchlauf ein zufälliges Element auswählst kann das ja auch zufällig das selbe sein. Wenn man mit einem Würfel 6 mal würfelt, dann bekommt man ja normalerweise nicht jede Möglichkeit einmal. Das kann zwar passieren ist aber recht unwahrscheinlich. (Auszurechnen wie (un)wahrscheinlich das ist überlasse ich dem geneigten Leser als Übungsaufgabe :-))

Ich würde vor dem Abfragen eine Liste mit Frage/Antwortpaaren erstellen, die mit der passenden Funktion aus `random` mischen, und dann in einer Schleife der nun zufälligen Reihenfolge nach abfragen.

Man könnte auch gleich mit so einer Liste mit Paaren anfangen statt ein Wörterbuch zu verwenden, denn der Zugriff über den Schlüssel auf den Wert wird ja im Programm überhaupt nicht benötigt.
lordzwieback
User
Beiträge: 55
Registriert: Montag 2. März 2015, 14:35
Kontaktdaten:

danke für die Hinweise @BlackJack, werd mir das mit den Listen mal anschauen.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

BlackJack hat geschrieben: ..., die mit der passenden Funktion aus `random` mischen, ...
(Nur um den Tipp noch stärker hervorzuheben :-) Dabei hilft - wie so oft - der englische Begriff weiter!)
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
lordzwieback
User
Beiträge: 55
Registriert: Montag 2. März 2015, 14:35
Kontaktdaten:

BlackJack hat geschrieben:Man könnte auch gleich mit so einer Liste mit Paaren anfangen statt ein Wörterbuch zu verwenden, denn der Zugriff über den Schlüssel auf den Wert wird ja im Programm überhaupt nicht benötigt.
Nur um sicher zu gehen, damit ich mir jetzt nicht die Arbeit umsonst mache: Meintest du mit "Liste mit Paaren" zwei Listen, jeweils mit "Frage" und "Antworten" drinne, die mit zip() zusammengeführt werden ?
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Du kannst auch eine Liste von Tupeln nehmen oder ein Tupel von Tupeln... ;-) Guck Dir mal Deine ``for``-Schleife an. Darauf bezog sich BlackJack. Du holst Dir da aktuell auch schon ein Paar von Schlüssel und Wert undkommst damit aus. Insofern muss die Struktur dahinter eben kein Dictionary sein.

Wieso sprichst Du jetzt ``zip`` an?
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
lordzwieback
User
Beiträge: 55
Registriert: Montag 2. März 2015, 14:35
Kontaktdaten:

Weil ich nach Sachen wie zB "Liste mit Paaren" und Ähnlichem gesucht habe, dabei bin ich beispielsweise auf das Verknüpfen von zwei Listen mittels zip() gestoßen.
BlackJack

@lordzwieback: Warum zwei getrennte Listen und dann `zip()`? Das was `zip()` als Ergebnis hat, kann man doch auch gleich als Datenstruktur schreiben. Dann hat man die Daten auch immer zusammen und muss wenn man etwas ändern möchte nicht in zwei getrennten Listen im Quelltext mühsam abzählen welche beiden Einträge zusammengehören.
Antworten