python 3.5 ja / nein Abfrage

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.
gonzo123
User
Beiträge: 3
Registriert: Montag 24. September 2018, 10:57

Hallo zusammen,

ich bin dabei python zu lernen, und bin noch am Anfang. Ich benutze python 3.5.
Jetzt habe ein kleines einfaches Programm geschrieben.
Habe aber ein Problem welches ich auch nach viel probieren nicht gelöst bekomme.
Ich möchte gerne das bei der nochmal-Abfrage nur y oder n eingegeben werden kann.
Gibt man etwas anderes als y oder n ein soll man solange nochmal eingeben bis y oder n richtig ist.
Ich bekomme es einfach nicht hin. Bestimmt gibt es andere und bessere Möglichkeiten das zu lösen.
Es wäre schön, wenn mit jemand helfen könnte.
Hier das Programm: -Bitte nicht lachen- bin noch am Anfang und möchte lernen.

Code: Alles auswählen

while True:
    vorname = input('Bitte Vorname eingeben: ')
    nachname = input('Bitte Nachname eingeben: ')
    alter = int(input('Alter eingeben: '))
    if alter <= 40:
        print('Dein Name ist',vorname,nachname,'und du bist',alter,'Jahre jung.')
    else:
        print('Dein Name ist',vorname,nachname,'und du bist',alter,'Jahre alt.')
    nochmal = input('Nochmal y oder n : ')
    if nochmal == 'y':
        print('Hier Nochmal!!!')
    elif nochmal == 'n':
        print('Das wars')
        break
    else:
        nochmal = input('Eingabe falsch - Bitte Nochmal y oder n : ')
        if nochmal == 'n':
            print('Programm beendet')
            break
Miranda
User
Beiträge: 23
Registriert: Sonntag 23. September 2018, 21:45

Hallo, Du musst natürlich für das erste while eine funktionierende Bedingung einbringen. Am besten als Variable.
Und Du musst auch bei der Eingabe des y/n eine while-Schleife machen, der Benutzer könnte sich ja mehrfach bei der Eingabe vertun.

Mal ohne weitere Kommentare könnte das so aussehen:

Code: Alles auswählen

eingabe = True
while eingabe:
    vorname = input('Bitte Vorname eingeben: ')
    nachname = input('Bitte Nachname eingeben: ')
    alter = int(input('Alter eingeben: '))
    if alter <= 40:
        print('Dein Name ist',vorname,nachname,'und du bist',alter,'Jahre jung.')
    else:
        print('Dein Name ist',vorname,nachname,'und du bist',alter,'Jahre alt.')
        
    auswahlJaNein = False
    while auswahlJaNein == False: 
        nochmal = input('Nochmal y oder n : ')
        if nochmal == 'y':
            eingabe = True
        elif nochmal == 'n':
            print('Das wars')
            eingabe = False
        else:
            print('Eingabe falsch - Bitte Eingabe wiederholen.', end = " ")
Benutzeravatar
__blackjack__
User
Beiträge: 13006
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Miranda: Es wäre besser die Nachfrage in eine Funktion auszulagern, dann braucht man nicht unnötig Variablen einführen, sondern kann bei ``while True`` bleiben.

Wahrheitswerte vergleicht man nicht mit literalen Wahrheitswerten. Da kommt ja eh nur wieder eine Wahrheitswert heraus, also kann man auch gleich den nehmen den man hat, oder dessen Negierung mit ``not``.

Code: Alles auswählen

#!/usr/bin/env python3


def ask_yes_no(prompt):
    while True: 
        answer = input('{} (y oder n): '.format(prompt))
        if answer == 'y':
            return True
        elif answer == 'n':
            return False
        else:
            print('Eingabe falsch - Bitte Eingabe wiederholen.', end=' ')


def main():
    while True:
        vorname = input('Bitte Vorname eingeben: ')
        nachname = input('Bitte Nachname eingeben: ')
        alter = int(input('Alter eingeben: '))
        print(
            'Dein Name ist {} {} und Du bist {} Jahre {}.'.format(
                vorname, nachname, alter, 'jung' if alter <= 40 else 'alt'
            )
        )
        if not ask_yes_no('Noch mal'):
            print('Das wars')
            break


if __name__ == '__main__':
    main()
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Sirius3
User
Beiträge: 17712
Registriert: Sonntag 21. Oktober 2012, 17:20

@Miranda: das mit der while-True-Schleife von gonzo123 war schon ok. Da spart man sich dann eine (oder hier zwei) Variable. Das bedeutet aber auch, dass man die Entscheidung nicht innerhalb der zweiten while-Schleife macht, sondern danach. Bei Dir wird die innere while-Schleife nie verlassen, weil sich auswahlJaNein nie ändert.

Code: Alles auswählen

while True:
    vorname = input('Bitte Vorname eingeben: ')
    nachname = input('Bitte Nachname eingeben: ')
    alter = int(input('Alter eingeben: '))
    jung = 'jung' if alter <= 40 else 'alt'
    print('Dein Name ist {} {} und du bist {} Jahre {}.'.format(vorname, nachname, alter, jung))
        
    while True:
        nochmal = input('Nochmal y oder n : ').lower()
        if nochmal in ['y', 'n']:
            break
        print('Eingabe falsch - Bitte Eingabe wiederholen.', end = " ")
    if nochmal == 'n':
        break
print('Das wars')
Miranda
User
Beiträge: 23
Registriert: Sonntag 23. September 2018, 21:45

Hallo und lieben Dank für den Hinweis. Ich hatte das nicht durchprobiert - meine Pausenzeit ist etwas zu knapp :oops:
Hier nur der Vollständigkeit halber die korrekte Version mit Variablen - so wie ich es in PHP oder Java gemacht hätte.

Code: Alles auswählen

eingabe = True
while eingabe == True:
    vorname = input('Bitte Vorname eingeben: ')
    nachname = input('Bitte Nachname eingeben: ')
    alter = int(input('Alter eingeben: '))
    if alter <= 40:
        print('Dein Name ist',vorname,nachname,'und du bist',alter,'Jahre jung.')
    else:
        print('Dein Name ist',vorname,nachname,'und du bist',alter,'Jahre alt.')
        
    auswahlJaNein = False
    while auswahlJaNein == False: 
        nochmal = input('Nochmal y oder n : ')
        
        if nochmal == 'y':
            auswahlJaNein = True
            eingabe = True
        elif nochmal == 'n':
            print('Das wars')
            auswahlJaNein = True
            eingabe = False  
        else:
            print('Eingabe falsch - Bitte Eingabe wiederholen.', end = " ")
            eingabe = False

Eure Lösungen mit while True und break sind tatsächlich eleganter :idea:
__deets__
User
Beiträge: 14494
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ich wuerde jetzt noch wie schon von __blackjack__ bemerkt auf die True/False in den Vergleichen verzichten. "eingabe == True" ist ja auch nur wieder True.

Code: Alles auswählen

while eingabe:
      ...
      while not auswahlJaNein:
          ...
Miranda
User
Beiträge: 23
Registriert: Sonntag 23. September 2018, 21:45

Wir haben das bei uns als Vorgabe wegen der Lesbarkeit :|
Klar, darüber kann man sich streiten. Ihr habt aber natürlich Recht - es ist nicht notwendig.
__deets__
User
Beiträge: 14494
Registriert: Mittwoch 14. Oktober 2015, 14:29

Also fuer mich ist das weniger lesbar, aber ja, da sind wir im tief im Fahrradschuppenland :)
Sirius3
User
Beiträge: 17712
Registriert: Sonntag 21. Oktober 2012, 17:20

Bis zu einem gewissen Grad ist weniger Text lesbarer als mehr Text, weil ein "== True" ja wirklich keinen Mehrwert bietet. Bei Vorgaben, die von dem Abweichen, was die restliche Community als Vorgabe hat, ist es wirklich erwägenswert, sich anzupassen.
Benutzeravatar
__blackjack__
User
Beiträge: 13006
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Um mal aus PEP8 zu zitieren:
Don’t compare boolean values to True or False using ==:

Yes:

if greeting:

No:

if greeting == True:
Das ist also die Meinung der Architekten des Fahradschuppens. :-)
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
__deets__
User
Beiträge: 14494
Registriert: Mittwoch 14. Oktober 2015, 14:29

Auch wenn wir in's off-topic abdriften... wir bekommen regelmaessig Bewerbungen mit Programmiertests in denen

Code: Alles auswählen

if cond:
    return True
else:
   return False
steht. Da rollen sich diverse Naegel. Und es gibt Punktabzug.
codemode89
User
Beiträge: 12
Registriert: Mittwoch 26. September 2018, 17:39

Es gibt noch ein Problem wenn man für das Alter ein Buchstaben eingibt. (ValueError:) beim cast.

Und um es gleich richtig zu lernen versuche die Methoden klein zu halten.

Benenne die Methoden so das man am Namen sieht was sie machen. Sollte dir kein guter Name für deine Methode einfallen,
ist es meist ein Zeichen dafür, das die Methode zu viele verschiedene dinge macht.

Und als weiterer Tipp nutze Englische Namen. Du wirst auf lange Sicht eh nicht ums englische drum herum kommen.

Code: Alles auswählen

def nochmal():
    eingabe_von_console = input('Nochmal y oder n : ').lower()
    while eingabe_von_console != "y" and eingabe_von_console != "n":
        eingabe_von_console = input('Nochmal y oder n : ').lower()
    return eingabe_von_console == "y"

def frage_nach_zahl(type="Zahl"):
    eingabe_von_console = input('Bitte {} eingeben: '.format(type))
    while not eingabe_von_console.isdigit():
        eingabe_von_console = input('Bitte {} eingeben: '.format(type))
    return int(eingabe_von_console)

def frage_nach_string(type="Zeichenkette"):
    eingabe_von_console = input('Bitte {} eingeben: '.format(type))
    while eingabe_von_console.isdigit():
        eingabe_von_console = input('Bitte {} eingeben: '.format(type))
    return eingabe_von_console

eingabe = True
while eingabe == True:
    vorname = frage_nach_string("Vorname")
    nachname = frage_nach_string("Nachname")
    alter = frage_nach_zahl("Alter")
    alters_definition = 'jung' if alter <= 40 else 'alt'
    print('Dein Name ist {} {} und du bist {} Jahre {}.'.format(vorname, nachname, alter, alters_definition))
    if not nochmal():
        eingabe = False
Benutzeravatar
sls
User
Beiträge: 480
Registriert: Mittwoch 13. Mai 2015, 23:52
Wohnort: Country country = new Zealand();

Miranda hat geschrieben: Mittwoch 26. September 2018, 08:11 Hier nur der Vollständigkeit halber die korrekte Version mit Variablen - so wie ich es in PHP oder Java gemacht hätte.

Code: Alles auswählen

eingabe = True
while eingabe == True:
    ....
Eure Lösungen mit while True und break sind tatsächlich eleganter :idea:
Das würde ich *so* in Java aber auch nicht machen, um ehrlich zu sein. Da reicht ein einfaches:

Code: Alles auswählen

boolean eingabe = true;

while (eingabe){
    ....
}
Anders als in Python wäre ohne Ausnahmebehandlung in Java kein "while (true)" möglich. Ich hatte die Diskussion mit der Bedingung zum Abbruch der Schleife hier in einem anderen Thread verfolgt und muss gestehen, dass ich in einigen Situationen ein while {condition} besser fände, als while True, da es je nach Komplexität der Schleife sofort klar ist *was* diese beendet. Auf SO gibt's dazu ja auch etliche Diskussionen: https://stackoverflow.com/questions/275 ... -condition
When we say computer, we mean the electronic computer.
Sirius3
User
Beiträge: 17712
Registriert: Sonntag 21. Oktober 2012, 17:20

@codemode89: ›frage_nach_string‹ fragt auch nach einer Zahl.

›while True:‹-Schleifen sind deshalb besser, weil man sich die Dopplung des ›input‹ spart:

Code: Alles auswählen

def nochmal():
    while True:
        eingabe_von_console = input('Nochmal y oder n : ').lower()
        if eingabe_von_console in ["y", "n"]:
            break
    return eingabe_von_console == "y"

def frage_nach_zahl(type="Zahl"):
    while True:
        eingabe_von_console = input('Bitte {} eingeben: '.format(type))
        if eingabe_von_console.isdigit():
            break
    return int(eingabe_von_console)
Benutzeravatar
__blackjack__
User
Beiträge: 13006
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@sls: Was ist denn mit diesem Satz gemeint: „Anders als in Python wäre ohne Ausnahmebehandlung in Java kein "while (true)" möglich.“

Und bei der besagten Eingabeschleife würde man in Java eine nachprüfende ``do``/``while``-Schleife machen anstatt einer ``while (bedingung) {…}``-Schleife um sich die Variable zu sparen. Im Gegensatz zu Python gibt es in Java ja eine nachprüfende Schleife.

Wenn man denn unbedingt alles in einer Methode abfühstücken möchte:

Code: Alles auswählen

import java.util.Scanner;
import java.util.function.BooleanSupplier;

final class Main {

    private Main() {}

    public static void main(String... args) {
        final var scanner = new Scanner(System.in);
        do {
            System.out.print("Bitte Vorname eingeben: ");
            final var vorname = scanner.nextLine();
            System.out.print("Bitte Nachname eingeben: ");
            final var nachname = scanner.nextLine();
            System.out.print("Alter eingeben: ");
            final var alter = scanner.nextInt();

            System.out.printf("Dein Name ist %s %s und Du bist %d Jahre %s.\n",
                    vorname, nachname, alter, (alter <= 40) ? "jung" : "alt");
        } while (((BooleanSupplier) () -> {
            while (true) {
                System.out.print("Nochmal (y oder n): ");
                switch (scanner.nextLine()) {
                    case "y":
                        return true;
                    case "n":
                        return false;
                }
                System.out.print("Eingabe falsch - Bitte Eingabe wiederholen. ");
            }
        }).getAsBoolean());
    }
}
Aber auch in Java würde ich die Funktionalität aufteilen:

Code: Alles auswählen

import java.util.Scanner;

final class Main {

    private static final Scanner SCANNER = new Scanner(System.in);

    private Main() {}

    private static String askString(String prompt) {
        System.out.print(prompt);
        return SCANNER.nextLine();
    }

    private static int askInteger(String prompt) {
        System.out.print(prompt);
        return SCANNER.nextInt();
    }

    private static boolean askYesNo(String prompt) {
        while (true) {
            System.out.printf("%s (y oder n): ", prompt);
            switch (SCANNER.nextLine()) {
                case "y":
                    return true;
                case "n":
                    return false;
            }
            System.out.print("Eingabe falsch - Bitte Eingabe wiederholen. ");
        }
    }

    public static void main(String... args) {
        do {
            final var vorname = askString("Bitte Vorname eingeben: ");
            final var nachname = askString("Bitte Nachname eingeben: ");
            final var alter = askInteger("Alter eingeben: ");

            System.out.printf("Dein Name ist %s %s und Du bist %d Jahre %s.\n",
                    vorname, nachname, alter, (alter <= 40) ? "jung" : "alt");
        } while (askYesNo("Nochmal"));
    }
}
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
codemode89
User
Beiträge: 12
Registriert: Mittwoch 26. September 2018, 17:39

@Sirius3
Sirius3 hat geschrieben: Mittwoch 26. September 2018, 19:54 @codemode89: ›frage_nach_string‹ fragt auch nach einer Zahl.
Nicht AUCH sondern NUR. Bei frage nach Zahl wird auf not isdigit() geprüft und bei frage_nach_string wird auf isdigit() geprüft.
Das macht auch Sinn
Wenn es eine Zahl ist (isdigit()) dann gehe in die schleife rein, weil eine Zahl nicht erwünscht ist.

Lese nochmal rüber oder probiere es aus.
Hat schon seine Richtigkeit :P

Achso und btw im Gegensatz zu den while true Konstrukt gehe ich bei meinem Code nur zum errorhandling in die while Schleife.
Treffen die Bedingungen zu skippe ich die Schleife.
codemode89
User
Beiträge: 12
Registriert: Mittwoch 26. September 2018, 17:39

@__blackjack__: Dein Javacode hat auch noch einen Fehler.

Wenn du mit einen Scanner nextInt() machst haste kein Lineskip.
Dadurch wird er in deiner askYesNo Methode immer einmal leer durchlaufen und in das errorhandling gehen.

Fix:

Code: Alles auswählen

    private static int askInteger(String prompt) {
        System.out.print(prompt);
        int inputByUser = SCANNER.nextInt();
        SCANNER.nextLine();
        return inputByUser;
    }
Benutzeravatar
sls
User
Beiträge: 480
Registriert: Mittwoch 13. Mai 2015, 23:52
Wohnort: Country country = new Zealand();

@codemode89:

hat man etwas dadurch verloren, wenn man das Alter via nextLine() einliest und dann als Integer parsed?

Code: Alles auswählen

    private static int askInteger(String prompt) {
        System.out.print(prompt);
        return Integer.parseInt(SCANNER.nextLine());
    }
@__blackjack__: wo kann man dich eigentlich am besten zur C-Programmierung befragen? :-)
When we say computer, we mean the electronic computer.
Benutzeravatar
__blackjack__
User
Beiträge: 13006
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@codemode89: Was mich an Deinem Code massiv stört sind die Code/Datenwiederholungen in allen drei Abfragefunktionen. Das ist eine negative Folge von der Eigenschaft das Du nur zur Fehlerbehandlung in die Schleife gehst, das Du dort alles noch mal machen musst.

Und die `frage_nach_zahl()` funktioniert nicht zuverlässig, weil der Benutzer etwas eingeben kann was zwar `isdigit()` erfüllt, aber dann nicht per `int()` in eine ganze Zahl umwandelbar ist. `int()` mag nur ASCII-Ziffern (wenn man bei der Basis 10 bleibt), `isdigit()` trifft aber auf so einige andere Unicode-Zeichen zu. Es ist also sinnvoller den `ValueError` bei `int()` entsprechend zu behandeln.

Letztlich fehlt beim Java-Code an der Stelle dann auch eine Fehlerbehandlung wenn keine Zahl eingegeben wird. Und beim Alter möchte man negative Werte vielleicht auch nicht zulassen. :-)

Code: Alles auswählen

    private static int askPositiveInteger(String prompt) {
        System.out.print(prompt);
        int result;
        while (true) {
            try {
                result = SCANNER.nextInt();
                if (result < 0) {
                    System.out.println("Bitte eine positive Zahl eingeben.");
                    continue;
                }
            } catch (InputMismatchException e) {
                System.out.println("Bitte eine Zahl eingeben.");
                continue;
            } finally {
                SCANNER.nextLine();
            }
            return result;
        }
    }
Da fehlt mir bei Java eindeutig das ``else`` zum ``try``. :-)

@sls: Gute Frage. Nächste Frage. :-)
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
codemode89
User
Beiträge: 12
Registriert: Mittwoch 26. September 2018, 17:39

sls hat geschrieben: Mittwoch 26. September 2018, 21:23 @codemode89:
hat man etwas dadurch verloren, wenn man das Alter via nextLine() einliest und dann als Integer parsed?
Ja das manuelle skippen ^^
__blackjack__ hat geschrieben: Mittwoch 26. September 2018, 21:25 @codemode89: Was mich an Deinem Code massiv stört sind die Code/Datenwiederholungen in allen drei Abfragefunktionen. Das ist eine negative Folge von der Eigenschaft das Du nur zur Fehlerbehandlung in die Schleife gehst, das Du dort alles noch mal machen musst.
Naja dafür lässt es sich aber besser lesen
Wie lange wird die schleife ausgeführt? while eingabe_von_console != "y" and eingabe_von_console != "n":

Ist besser als "while true" wo du erstmal nach nem break oder return suchen musst.

Man muss immer einen Mittelweg aus Lesbarkeit und Code Ersparnis finden. Zumal ich denke das da überhaupt keine Duplizierung drinne ist.
Um einen Wert zu prüfen muss man ihn halt einmal abfragen. Stimmt er nicht musst du ihn neu setzen. Was anderes machst du in deiner while true auch nicht.


__blackjack__ hat geschrieben: Mittwoch 26. September 2018, 21:25 Und die `frage_nach_zahl()` funktioniert nicht zuverlässig, weil der Benutzer etwas eingeben kann was zwar `isdigit()` erfüllt, aber dann nicht per `int()` in eine ganze Zahl umwandelbar ist. `int()` mag nur ASCII-Ziffern (wenn man bei der Basis 10 bleibt), `isdigit()` trifft aber auf so einige andere Unicode-Zeichen zu. Es ist also sinnvoller den `ValueError` bei `int()` entsprechend zu behandeln.
https://python-reference.readthedocs.io ... digit.html
Hast du ein Beispiel für etwas das zum Fehler führen könnte? oO
Antworten