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.
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: 13004
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
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@codemode89: Ganze 50% wiederholter Code in jeder der drei Funktionen ist keine Code-Duplizierung für Dich? :-o

Ein Beispiel für nicht-ASCII-Ziffern? Wie wär's mit 698:

Code: Alles auswählen

In [25]: ds = list(filter(str.isdigit, (chr(i) for i in range(0x110000))))

In [26]: len(ds)
Out[26]: 708
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

@__backjack__: `int` mag auch arabische Ziffern:

Code: Alles auswählen

int("۵۷")
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Stimmt. Also noch ein bisschen mehr filtern:

Code: Alles auswählen

In [59]: def f(x):
    ...:     try:
    ...:         int(x)
    ...:         return True
    ...:     except:
    ...:         return False
    ...:     

In [60]: ds2 = [x for x in ds if not f(x)]

In [61]: len(ds2)
Out[61]: 128
Ums mal praktisch zu machen: ich hatte es mit etwas getestet was auf deutschen Tastaturlayouts einfach einzugeben ist: ² (Alt Gr + 2). Das mag `int()` beispielsweise nicht.
“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

__blackjack__ hat geschrieben: Mittwoch 26. September 2018, 22:09 @codemode89: Ganze 50% wiederholter Code in jeder der drei Funktionen ist keine Code-Duplizierung für Dich? :-o
Das ist korrekt.

Code: Alles auswählen

i=0
while i <10
	i+=1
return i
Hast du da auch 50% Dopplung?
Das ist ein Standardkonstrukt und für jeden leicht lesbar.

Ich verstehe deinen Standpunkt ja, es wird ja auch teilweise in Python Fachliteratur so angeraten mit dem while true , aber ich sehe es halt anders.
Ich empfehle dir mal das Buch Clean Code von Robert C. Martin zu lesen. (Soll weder einen Angriff darstellen, noch deine Expertise in Frage stellen)

Der Tipp mit isdigit() ist super! Vielen Dank dafür :) wieder was dazu gelernt.

Aber ich würde trotzdem kein Int cast mit try/catch machen, sondern würde dann eher ein pattern matching verwenden.

Code: Alles auswählen

def is_valid_number(number_string):
    return not re.fullmatch('\d+', number_string, re.A) is None
Genauso in Java: try catch finally alles unötige code Aufblähung.
Das oberste Ziel sollte sein den Code gut lesbar und somit leicht wartbar zu machen.

Code: Alles auswählen

private static boolean isValidNumber(String validationObject) {
	return validationObject.matches("[0-9]+");		
}

private static int askForAge(String prompt) {
	String consoleInput;
	do {
		System.out.println(prompt);
		consoleInput = SCANNER.nextLine();
	}while(!isValidNumber(consoleInput));
	return Integer.parseInt(consoleInput);
}
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

Idiome aus einer Sprache unhinterfragt in andere zu uebertragen ist keine gute Idee. So gut Clean Code ist, es bezieht sich auf die bei MS zu der Zeit genutzten Sprachen. Explizite Zaehlvariablen sind in Python verpoent, weil sich die meisten Probleme in denen sie verwandt werden eh besser durch Iteratoren darstellen lassen. Eine Lektion, die inzwischen auch andere Sprachen gelernt haben, Java inklusive.

Und damit definiert sich die Lesbarkeit nicht absolut, sondern relativ zur Sprache, und da sind while True: break und try/excepts eben das Mittel der Wahl. Und erst recht nichth so ein i=0, while-Konstrukt wie du es oben praesentierst. Natuerlich geht es auch anders, was ja das unterliegende Grundproblem aller solcher Diskussionen ist: es tut ja. GOTO-Wuesten und ungarische Notation tun es auch. Will aber keiner mehr sehen.
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

@codemode89: das Patternmatching ist entweder nicht ausreichend oder schränkt zu sehr ein. Ausnahmen mit try-Block sind ja gerade dazu da, bei Falscheingaben entsprechend reagieren zu können. Das Pattern zu verstehen ist um einiges komplizierter, als der fast schon literarische Text: "versuche: wandle Text in Zahl. Falls das nicht klappt, sage, 'das war keine Zahl' ".

Code: Alles auswählen

def frage_nach_zahl(type="Zahl"):
    while True:
        eingabe_von_console = input('Bitte {} eingeben: '.format(type))
        try:
            return int(eingabe_von_console)
        except ValueError:
            pass # keine Zahl eingegeben
Bei

Code: Alles auswählen

i=0
while i <10
	i+=1
return i
gibt es keine Code-Dopplung, weil i ja zwingend initialisiert werden muß um dann bei i+=1 damit weiter rechnen zu können. Dagegen ist es einfach nur das falsche Konstrukt, da das durch eine for-Schleife ausgedrückt werden kann

Code: Alles auswählen

for i in range(10):
    pass
return i
Und da die for-Schleife nichts macht, außer den Zähler hochzuzählen, kann man das zu

Code: Alles auswählen

return 9
verwandeln.
codemode89
User
Beiträge: 12
Registriert: Mittwoch 26. September 2018, 17:39

__deets__ hat geschrieben: Donnerstag 27. September 2018, 09:02Und erst recht nichth so ein i=0, while-Konstrukt wie du es oben praesentierst.
Ähm das war nur ein Beispiel wie eine Standard while schleife definiert ist.

Code: Alles auswählen

condition
while(!condition)
	do something
	
Mir ist schon klar das es mit Integern schönere Wege gibt, man hat aber nicht immer Integer.
Und der Grundzustand einer condition kommt nicht aus der Luft gefallen sondern bedarf einer Zuweisung.

Und ob es nun nicht der Pythonic way ist steht auf einen anderen Blatt. Das habe ich ja auch eingeräumt, und es ist ja völlig legitim
codemode89 hat geschrieben: Donnerstag 27. September 2018, 08:30 Ich verstehe deinen Standpunkt ja, es wird ja auch teilweise in Python Fachliteratur so angeraten mit dem while true , aber ich sehe es halt anders.
Clean Code ist schön älter ja, aber es behandelt etliche zeitlose Konzepte unabhängig von jeglicher Programmiersprache.


Sirius3 hat geschrieben: Donnerstag 27. September 2018, 09:16 gibt es keine Code-Dopplung, weil i ja zwingend initialisiert werden muß um dann bei i+=1 damit weiter rechnen zu können.
i muss schon initialisiert werden für die condition, das ist exakt das was ich bei meiner Funktion auch gemacht habe.
Sirius3 hat geschrieben: Donnerstag 27. September 2018, 09:16 @codemode89: das Patternmatching ist entweder nicht ausreichend oder schränkt zu sehr ein. Ausnahmen mit try-Block sind ja gerade dazu da, bei Falscheingaben entsprechend reagieren zu können. Das Pattern zu verstehen ist um einiges komplizierter, als der fast schon literarische Text: "versuche: wandle Text in Zahl. Falls das nicht klappt, sage, 'das war keine Zahl' ".
Wie machst du es denn das er nur 0-9 als Input akzeptiert?
Was ist wenn die Zahl dann nur zwischen 0 bis 130 sein darf?
Kommen wir dann nicht wieder zu try if else except?

Naja mir soll es im Endeffekt auch egal sein :P.
Ich denke ich habe meinen Standpunkt klar gemacht. Ihr habt euren Standpunkt klar gemacht.
Und wir werden in der Hinsicht wohl nicht zueinander finden.

Zum try, except als mittel der Wahl, siehe den Javacode.
Wenn du

Code: Alles auswählen

while true
	try
		if
		continue
	catch
		continue
	finally
leserlicher findest als

Code: Alles auswählen

do
while(condition)
dann ist das wohl so und das akzeptiere ich ja auch.

In Python ist es auch weniger performant jedes mal in try except zu gehen und wie bereits erwähnt,
ist es MEINER Meinung weniger leserlich als eine konkrete condition.

Da ich neu im Forum bin wollte ich abschließend nur nochmal klar stellen, das ich hier niemanden persönlich angreifen wollte.
Ich denke auch nicht das mein Weg der einzig richtige ist, sondern habe nur meine Meinung kund getan, wofür das Forum ja nun auch da ist.

Ich will mir hier ja keine Feinde machen sondern Freunde für einen tollen Austausch :P
Miranda
User
Beiträge: 23
Registriert: Sonntag 23. September 2018, 21:45

codemode89 hat geschrieben: Mittwoch 26. September 2018, 17:58 Und als weiterer Tipp nutze Englische Namen. Du wirst auf lange Sicht eh nicht ums englische drum herum kommen.
Das dachte ich auch mal :lol:
Bis ich dann das erste mal in einem deutsch, weißrussisch, spanischen Team gearbeitet habe und deutsch tatsächlich die einzige Sprache war, die alle verstanden haben.
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@codemode89: Bei der ``while``-Schleife sehe ich keine Code-Dopplung. Du etwa? Welchen Teilausdruck davon könnte man denn nur einmal schreiben wenn man das anders ausdrückt?

Diese Schleife ist so auch kein Standardkonstrukt, wie ja bereits gesagt wurde. Auch in vielen anderen Programmiersprachen würde man hier standardmässig eine ``for``-Schleife verwenden. Ansonsten könnte man ja auch GOTO in einem leicht verständlichen Standardkonstrukt verwenden (braucht das externe `goto-statement`-Package):

Code: Alles auswählen

from goto import with_goto


@with_goto
def f():
    i = 0
    label .loop_start
    if i >= 9: goto .loop_end
    i += 1; goto .loop_start
    label .loop_end
    return i
Das ist aber genau wie die ``while``-Schleife kein idiomatisches Python.

In „Clean Code“ hatte ich schon mal geblättert, und ich kann mir schwer vorstellen, dass Uncle Bob empfiehlt das DRY-Prinzip zu verletzen. Das ist eines der zeitlosen und ziemlich grundlegenden Konzepte.

Was ist denn in *Python* an einer Ausnahmebehandlung aufgeblähter als an einer Fallunterscheidung? Bei Java stimmt das, da ist das sowohl vom Code her unhandlicher weil es kein ``else`` gibt, als auch von der Laufzeit, weil Ausnahmebehandlung dort verhältnismässig teuer ist, was sie in Python nicht ist! Da sind Funktionsaufrufe mindestens genau so teuer. Deswegen soll man in Java Ausnahmen auch nicht für normale Steuerung des Programmflusses verwenden. In Python ist das dagegen normal. Jede ``for``-Schleife wird in Python durch eine `StopIteration`-Ausnahme beendet. Das explizit angeforderte Programmende wird durch eine `SystemExit`-Ausnahme geregelt.

Das ist eben idiomatisches Python. Dazu mal zwei Einträge aus dem Glossar der Python-Dokumentation:
EAFP
Easier to ask for forgiveness than permission. This common Python coding style assumes the existence of valid keys or attributes and catches exceptions if the assumption proves false. This clean and fast style is characterized by the presence of many try and except statements. The technique contrasts with the LBYL style common to many other languages such as C.

[…]

LBYL
Look before you leap. This coding style explicitly tests for pre-conditions before making calls or lookups. This style contrasts with the EAFP approach and is characterized by the presence of many if statements.
Und wirklich aufgebläht finde ich das hier auch in Java nicht:

Code: Alles auswählen

    private static int askPositiveInteger(String prompt) {
        while (true) {
            try {
                return Integer.parseUnsignedInt(askString(prompt));
            } catch (NumberFormatException e) {
                System.out.println("Bitte eine positive ganze Zahl eingeben!");
            }
        }
    }
Der Code mit dem ``continue`` ist in der Tat schrecklich, aber das hätte man in Python so ja nicht, denn da gibt es das ``else`` was es in Java nicht gibt *und* eine Quelle von Komplexität ist hier ja auch das man in jedem Fall den Scanner noch das Zeilenende schlucken lassen muss. Sonst kann man sich den ``finally``-Zweig sparen. Wie man an dem letzten Codebeispiel gut sehen kann. Ich finde das jedenfalls nicht unleserlicher als eine ``do``/``while``-Schleife. In Java kann man dann überlegen was man nehmen will, in Python nicht. Denn eine ``do``/``while``-Schleife gibt es als Syntaxkonstrukt nicht.

Zum `is_valid_number()` fällt auf das da ``not`` gefolgt von einem recht langem Ausdruck und dann ein ``is None`` steht. Das kann man sehr leicht übersehen und sollte deshalb besser als ``[…] is not None`` geschrieben werden. Oder man lässt das einfach komplett weg, denn ein `Match`-Objekt ist ja immer ”wahr” und `None` ist immer ”unwahr” in boole'schen Kontexten.
“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

__blackjack__ hat geschrieben: Donnerstag 27. September 2018, 10:54 Diese Schleife ist so auch kein Standardkonstrukt, wie ja bereits gesagt wurde. Auch in vielen anderen Programmiersprachen würde man hier standardmässig eine ``for``-Schleife verwenden. Ansonsten könnte man ja
War wie jetzt zum dritten mal gesagt nur ein Beispiel um den Aufbau

Code: Alles auswählen

condition
while (!condition)
	do something
zu verdeutlichen. (Rede ich gegen Wände?)

Eine for Schleife sollte eingesetzt werden wenn das Ende vor dem Beginn absehbar ist.
Trifft hier nicht zu da der User 100 oder auch 1000 mal falsche Eingaben machen kann.

Eine while Schleife sollte man einsetzen wenn das Ende vorher nicht absehbar ist.

DRY Prinzip verletzt in dem ich eine Variable initialisiere? Ich denke nicht.
Nochmal DRY Prinzip nachlesen und verstehen was da der ausschlaggebende Punkt ist.

Diese Methode

Code: Alles auswählen

    private static int askPositiveInteger(String prompt) {
        while (true) {
            try {
                return Integer.parseUnsignedInt(askString(prompt));
            } catch (NumberFormatException e) {
                System.out.println("Bitte eine positive ganze Zahl eingeben!");
            }
        }
    }
macht 2 Sachen, sie liest von der Console ein und prüft den Input.

Jede Methode sollte genau eine Sache machen.
Wenn das Alter jetzt zwischen 30 und 100 sein soll, wie sieht es dann aus?

Code: Alles auswählen

	    private static int askPositiveInteger(String prompt) {
	        while (true) {
	            try {
	                int number = Integer.parseUnsignedInt(askString(prompt));
	                if(number>30 && number<100)
	                	return number;
	            } catch (NumberFormatException e) {
	                System.out.println("Bitte eine positive ganze Zahl eingeben!");
	            }
	        }
	    }
Jetzt bitte einmal extrahieren und bei deiner while true schleife bleiben.
__blackjack__ hat geschrieben: Donnerstag 27. September 2018, 10:54 Zum `is_valid_number()` fällt auf das da ``not`` gefolgt von einem recht langem Ausdruck und dann ein ``is None`` steht. Das kann man sehr leicht übersehen und sollte deshalb besser als ``[…] is not None`` geschrieben werden. Oder man lässt das einfach komplett weg, denn ein `Match`-Objekt ist ja immer ”wahr” und `None` ist immer ”unwahr” in boole'schen Kontexten.
Hast du zu 100% recht.
codemode89
User
Beiträge: 12
Registriert: Mittwoch 26. September 2018, 17:39

__blackjack__ hat geschrieben: Donnerstag 27. September 2018, 10:54 Das ist eben idiomatisches Python. Dazu mal zwei Einträge aus dem Glossar der Python-Dokumentation:
EAFP
Easier to ask for forgiveness than permission. This common Python coding style assumes the existence of valid keys or attributes and catches exceptions if the assumption proves false. This clean and fast style is characterized by the presence of many try and except statements. The technique contrasts with the LBYL style common to many other languages such as C.

[…]

LBYL
Look before you leap. This coding style explicitly tests for pre-conditions before making calls or lookups. This style contrasts with the EAFP approach and is characterized by the presence of many if statements.
Darauf gehe ich nicht weiter ein mehr als 2 mal zu bestätigen das ihr Recht habt, das es nicht der pythonic way ist kann ich auch nicht tun ^^
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

codemode89 hat geschrieben: Donnerstag 27. September 2018, 11:47
DRY Prinzip verletzt in dem ich eine Variable initialisiere? Ich denke nicht.
Nochmal DRY Prinzip nachlesen und verstehen was da der ausschlaggebende Punkt ist.
Das bezog sich auf deine drei Input-Methoden, die alle bis auf Text & Praedikat das gleiche machen. Und in einer Sprache, in der Funktionen Mitbuerger erster Klass sind, ist beides problemlos loesbar ohne sich so viel zu wiederholen. Und die while-Schleife ist nun schon mehrfach nicht wegen DRY, sondern unidiomatischem Python-Code angesprochen worden. Auch anderswo stehen augenscheinlich Waende rum.
codemode89
User
Beiträge: 12
Registriert: Mittwoch 26. September 2018, 17:39

__deets__ hat geschrieben: Donnerstag 27. September 2018, 11:53 Und die while-Schleife ist nun schon mehrfach nicht wegen DRY, sondern unidiomatischem Python-Code angesprochen worden. Auch anderswo stehen augenscheinlich Waende rum.
siehe mein letzten Post
__deets__ hat geschrieben: Donnerstag 27. September 2018, 11:53 Das bezog sich auf deine drei Input-Methoden, die alle bis auf Text & Praedikat
und return type.
__deets__ hat geschrieben: Donnerstag 27. September 2018, 11:53 das gleiche machen.
Jede get_input Methode hat eine eigene condition sowie ein anderen return value das einzige was sie sich teilen ist das in jeder eine while schleife läuft

Bitte einmal Code Beispiel wie das sonst zu erreichen ist. Ich bin ja lernwillig
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@codemode89: Der Aufbau war in deinem praktischen Beispiel

Code: Alles auswählen

condition = [code und daten die die bedingung ausmachen]
while (!condition)
    do something
    condition = [code und daten die die bedingung ausmachen]
Und das in den eckigen Klammern stand da zweimal identisch im Code und war nicht nur ein trivialer Aufruf, müsste also auch an beiden Stellen gleich geändert werden, wenn man etwas Ändern oder einen Fehler beheben möchte, und verletzt damit das DRY-Prinzip.

`askPositiveInteger()` macht genau eine Sache: Den Benutzer solange nach einer Eingabe fragen bis der eine positive, ganze Zahl eingegeben hat. Das ist auf dieser Abstraktionsebene ein Schritt. Ansonsten würde dieses Argument ja gegen jede Methode sprechen die mehr als eine Operation beinhaltet und `main()`-Methoden komplett verboten machen, denn die machen ja *alles*!

Eine Methode die eine ganze Zahl mit Unter- und Obergrenze abfragt, würde in der Tat so ähnlich aussehen. Ungefähr so:

Code: Alles auswählen

    private static int askAge(int lowerLimit, int upperLimit) {
        if (lowerLimit > upperLimit) {
            throw new IllegalArgumentException("lower limit must not be greater than upper limit");
        }
        while (true) {
            try {
                final var result = Integer.parseInt(askTrimmedNonEmptyString("Alter eingeben: "));
                if (lowerLimit <= result && result <= upperLimit) {
                    return result;
                }
                System.out.printf(
                        "Bitte eine Zahl zwischen %d und %d (inklusive) eingeben!",
                        lowerLimit, upperLimit);
            } catch (NumberFormatException e) {
                System.out.println("Bitte eine ganze Zahl eingeben!");
            }
        }
    }
Was ich da jetzt extrahieren soll ist mir allerdings nicht klar‽ Und warum?
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ein Beispiel wie man eine wiederholte Eingabe ohne Code-Duplizierung und mit klarer Abtrennung von Fehlerbedingung gestalten koennte:

Code: Alles auswählen

def ask_until_correct(message, errormessage, conversion):
    while True:
        try:
            return conversion(input(message))
        except ValueError:
            print(errormessage)


def alterspraedikat(value):
    alter = int(value)
    if 1 <= alter <= 120:
        return alter
    raise ValueError


def namenspraedikat(value):
    if not len(value):
        raise ValueError
    return value


def ja_nein_frage(value):
    try:
        return dict(j=True, y=True, n=False)[value.lower()[0]]
    except (IndexError, KeyError):
        raise ValueError


def main():
    alter = ask_until_correct(
        "Bitte Alter angeben: ",
        "Falsche Eingabe, Alter zwischen 1 und 120",
        alterspraedikat,
    )
    name = ask_until_correct(
        "Bitte Namen angeben: ",
        "Falsche Eingabe. Ein Name kann nicht leer sein",
        namenspraedikat,
    )
    raucher =  ask_until_correct(
        "Sind Sie Raucher?",
        "Bitte mit Ja/ja/yes/j/y oder Nein/nein/no/n antworten",
        ja_nein_frage,
    )
    print("hallo", name, "im Alter von", alter)
    print("Rauchen ist ungesund" if raucher else "Nichtraucher haben bessere Zaehne")


if __name__ == '__main__':
    main()
Zuletzt geändert von __deets__ am Donnerstag 27. September 2018, 13:13, insgesamt 1-mal geändert.
Grund: Fehler in namens-test repariert
Antworten