Eingabenprüffunktion

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
derrick
User
Beiträge: 34
Registriert: Mittwoch 8. Juni 2011, 20:32

Abend Leute,
es kommt ja ab und an mal vor, dass man prüfen muss ob der input eines Benutzers z.B. eine Zahl ist , damit ein Programm richtig funktioniert. Ich habe mir überlegt ob es z.B. sinnvoll wäre eine derartige Funktion zu schreiben:

Code: Alles auswählen

def int_input():
	try:
		digit = int(input("Enter a number: "))
		return digit
	except:
		print("Only numbers are allowed")
		int_input()
Dann kann man es sich sparen bei jeder Benutzereingabe in einem beliebigen Modul eine Überprüfung durchzuführen.
Natürlich ist obiges auch für so ziemlich jede andere Eingabe wie z.B. Buchstaben (.isalpha()) denkbar.
Was haltet ihr von einem solchen Vorgehen und gibt es soetwas möglicherweise schon vorgefertigt.

Grüße
derrick
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

So eine Funktion ist generell eher weniger sinnvoll. Man will beispielsweise nicht immer eine Schleife, solange kein gültiger Wert übergeben wird. Wenn man die Funktion, um eine Option dafür erweitert, hat man am Ende mehr Ärger als Nutzen.

Konkret an der Implementierung: Man will eigentlich ein Prompt übergeben, der Nutzer wird sich freun, wenn man ihm sagt, dass er eine Zahl übergeben soll, aber nicht was sie repräsentiert.

Desweiteren ist die Rekursion unnötig und da Python nur eine bestimmte Rekursionstiefe zulässt, stösst man schnell an die Grenzen.
deets

@cofi

Bei der Rekursionstiefe von Python ist wohl eher davon auszugehen, dass die Grenzen der Belastbarkeit des Dateneingebers eher erreicht ist ;) Aber elegant ist anders, ja.

@derrick

Sowas gibt es in gewisser Weise schon, zb formencode. Das ist zwar eigenlich dazu gedacht, HTTP-Requests zu validieren & konvertieren. Aber fuer diesen Zweck ginge es auch. Dann ist die (nicht-rekursive..) Implementation trivial.

Code: Alles auswählen

from formencode import Invalid
from formencode.validators import Int


def safe_input(validator, message="", error_msg="falsche eingabe"):
    while True:
        raw = raw_input(message)
        try:
            return validator.to_python(raw)
        except Invalid:
            print error_msg

print safe_input(Int())
Aber mir ehrlich gesagt nicht weiter wert, weil so simpel, dass sie sich bei Bedarf eben schnell schreibt, wie man sie gerade en detail braucht.
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

cofi hat geschrieben:So eine Funktion ist generell eher weniger sinnvoll.
Warum? Wenn man desöfteren eine Zahl als Eingabe verlangt, macht eine Funktion zur Validierung doch Sinn. Ok, die von derrick gezeigte Funktion ist nicht ganz glücklich, aber grundsätzlich...
Ich würde das halt ohne try: ... except: machen:

Code: Alles auswählen

def valid(spec, prompt, end='xX'):
    spec = spec.upper()
    test = {'DI': 'isdigit', 'AL': 'isalpha', 'AN': 'isalnum'}
    value = input(prompt)
    while not value in end and not getattr(value, test[spec])():
        print('Bitte wiederholen Sie Ihre Eingabe!')
        value = input(prompt)
    return value
Die Funktion überprüft, ob die Eingabe mit einer vorgegebenen 'spec' übereinstimmt und gibt diese Eingabe dann unverändert als string zurück.
Abbrechen lässt sich die Schleife durch ein in 'end' enthaltenes Zeichen.

mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

@mutella: EAFP verlangt von dir geradezu, dass du das Problem mit Exceptions löst ;-) Ich würde deine Lösung in etwa so anpassen:

Code: Alles auswählen

import functools
def ask(question, type_, stop="", default=None):
    for value in iter(functools.partial(raw_input, question), stop):
        try:
            return type_(value)
        except ValueError:
            pass
    return default
Das Leben ist wie ein Tennisball.
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

mutetella hat geschrieben:
cofi hat geschrieben:So eine Funktion ist generell eher weniger sinnvoll.
Warum? Wenn man desöfteren eine Zahl als Eingabe verlangt, macht eine Funktion zur Validierung doch Sinn.
Das steht im Satz danach. Und das ist auch nur ein Beispiel. Wenn man das natuerlich im eigenen Code desoefteren genauso braucht, kann man das durchaus machen, aber eine allgemein brauchbare Funktion ist nicht sonderlich hilfreich.

@deets: Wir reden hier von Eingaben der boesen User ;) Und so ein boeser User kann das auch problemlos automatisieren.
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

@EyDu:
Was für ein Unterschied! Mein zusammengeschusterter Code und Deine schöne, kompakte Lösung! Cool!

Für den OP, der mit Python 3 arbeitet, sei noch gesagt, dass 'raw_input' durch 'input' zu ersetzen ist.

mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
problembär

mutetella hat geschrieben:@EyDu:
Was für ein Unterschied! Mein zusammengeschusterter Code und Deine schöne, kompakte Lösung! Cool!
Die Schönheit liegt (mal wieder) im Auge des Betrachters. Ich habe bei solchen "kompakten Lösungen" Verständnisprobleme.
Ich würde mich daher nahe an dem Vorschlag des OP halten, allerdings die Rekursion vermeiden:

Code: Alles auswählen

#!/usr/bin/env python
# coding: iso-8859-1

def int_input(question):
    digit = None
    while digit == None:
       try:
           digit = int(raw_input(question))
           return digit
       except ValueError:
          print("Only numbers are allowed.")

print int_input("Enter a number: ")
Gruß
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Was ist denn an meinem gezeigten Ansatz nicht sofort verständlich? Mich stören zum Beispiel eher die überflüssige Bedingung und ein unnötiger Name welcher eine vollkommen triviale Zeile erzeugt ;-)

Code: Alles auswählen

def int_input(question):
    while True
       try:
           return int(raw_input(question))
       except ValueError:
          print "Only numbers are allowed."
Das Leben ist wie ein Tennisball.
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

problembär hat geschrieben:Die Schönheit liegt (mal wieder) im Auge des Betrachters.
Du hast sicher Recht, über Schönheit lässt sich streiten. Die Kompaktheit von EyDu's Beispiel hat aber neben seiner Schönheit einen unbestreitbaren Vorteil. Der Einsatz von 'iter' an dieser Stelle spart eine zusätzliche Abfrage, um die Eingabeschleife auch abbrechen zu können.
Dein Beispiel ist auf den ersten Blick natürlich leichter lesbar. Um allerdings ein Abbrechen zu ermöglichen, müsste ein Aufwand betrieben werden, der durch 'iter' erspart bleibt.

mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
Antworten