Python: Funktion gibt über return 'None' zurück?

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
xhera
User
Beiträge: 2
Registriert: Sonntag 6. August 2017, 13:36

Hallo Python Community,

ich bin erst vor kurzem an die Python-Programmierung geraten, und habe deshalb noch recht wenig Ahnung. Lernen tue ich mit einem Buch für Programmieranfänger. Jetzt gab es am Ende mehrerer Kapital eine Abschlussaufgabe zu meistern, die ich ohne Hilfe des Buches FAST komplett programmiert habe (deshalb kann ich durchs Buch auch nicht meinen persönlichen Fehler korrigieren). Man soll einem Benutzer bis zu 10 Rechenaufgaben stellen.Wie viele es von 1-10 seien sollen entscheidet der Benutzer durch Eingabe selbst. Zahlen sollen 'random' sein, welche Rechenzeichen wann drankommen ist auch random, und je nachdem was für ein Rechenzeichen entstanden ist, sind die Zahlenbereiche unterschiedlich. Pro Aufgabe hat der Benutzer 3 Versuche usw...

+,- und * hat Anfangs einwandfrei funktioniert sprich die Aufgaben wurden generiert und die Auswertung mit dem Lösungsvorschlag des Benutzers wurde durchgeführt. Ich habe dann / mit reingenommen und dann hat die Funktion das Musterergebnis manchmal, nicht immer, als 'None' zurückgeliefert (für jede Rechenart). Ich sitze seit gestern Nacht dran, und glaube nicht, dass ich es selbst schaffe den Fehler zu finden. Also bitte ich hier um Hilfe, sonst werd ich noch verrückt :evil:

Code: Alles auswählen

def aufgabe_generieren():
     op = random.randint(1,4)
 
     # +
     if op is 1:
         a = random.randint(1,50)
         b = random.randint(1,50)
 
         print("Die Aufgabe ist: ",a,"+",b)
         ergebnis = a + b
         return ergebnis
 
    #op = 2 & 3 weggelassen
    
    # /
    elif op is 4:
         a = random.randint(1,20)
         b = random.randint(1,20)
 
         if a > b and a % b == 0:                               
              print("Die Aufgabe ist: ",a,"/",b)
              ergebnis = a / b                                     #Hier ist Ergebnis noch normal
              return ergebnis                            
 
         else:
                 aufgabe_generieren() 

#Funktion wird jetzt in einer While-Schleife so oft aufgerufen, wie Benutzer Aufgaben haben wollte.

LG xhera
Zuletzt geändert von Anonymous am Sonntag 6. August 2017, 14:00, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Codebox-Tags gesetzt.
nezzcarth
User
Beiträge: 1635
Registriert: Samstag 16. April 2011, 12:47

Das Problem entsteht durch den rekursiven Aufruf in Zeile 26. Wenn der Aufruf beendet ist, d.h. ein return Statement erreicht wurde, wird an die Stelle zurück gesprungen. Der Rückgabewert von "aufgabe_generieren" geht dabei verloren, da du diesen nicht zurück gibst. Mein Vorschlag wäre, für den Anfang eine Lösung ohne Rekursion zu suchen.
Zuletzt geändert von nezzcarth am Sonntag 6. August 2017, 14:21, insgesamt 1-mal geändert.
BlackJack

@xhera: Also erst einmal ist der Vergleich mit ``is`` hier falsch, auch wenn der zufälligerweise bei CPython wahrscheinlich immer funktionieren wird. Du möchtest wissen ob die Werte gleich sind (`==`), nicht ob das Objekt das selbe ist (``is``). Das muss nämlich nicht das selbe sein um den gleichen Wert zu haben:

Code: Alles auswählen

In [10]: a is b
Out[10]: False

In [11]: a == b
Out[11]: True

In [12]: a
Out[12]: 4711

In [13]: b
Out[13]: 4711
Wenn dieser Fehler behoben ist, dann hast Du da den letzten Fall, die Division, wo im ``else``-Zweig nichts zurückgegeben wird, womit `aufgabe_gererieren()` am Ende der Funktion ankommt, wo man sich immer ein implizites ``return None`` vorstellen kann. Du müsstest den Rückgabewert des rekursiven Aufrufs auch an den ursprünglichen Aufrufer zurückgeben.

Allerdings sollte man das hier sowieso nicht durch einen rekursiven Aufruf lösen. Rekursive Aufrufe haben Grenzen und man sollte sie nicht als Ersatz für einfache Schleifen missbrauchen.

Äquivalent zu dem Aufruf wäre an der Stelle das ``else`` einfach weg zu lassen und um den gesamten Code in der Funktion eine ``while True:``-Schleife zu legen.

Das wäre aber IMHO immer noch falsch, denn dadurch das nur bei der Division es passieren kann das die Aufgabenerstellung noch einmal von vorne losgehen kann, sind Aufgaben mit Division weniger wahrscheinlich. Dafür müsste man die ``while True:``-Schleife nur um den Teil legen der die Divisionsaufgabe erzeugt.

Man könnte die Divisionsaufgabe auch anders erzeugen, so dass man ohne mögliche Wiederholungen eine Aufgabe erzeugt. Man muss ja nicht die beiden Operanden für eine Operation erzeugen, man kann auch einen Operanden und das Ergebnis erzeugen, und den anderen Operanden daraus berechnen.
xhera
User
Beiträge: 2
Registriert: Sonntag 6. August 2017, 13:36

Okay vielen dank für eure Antworten! Die while true-Schleife hatte ich auch ursprünglich um die Division drinnen, hatte leider einen kleinen Fehler, und habe deswegen den jetzt fehlerhaften Teil dann reingepackt. Bezüglich 'is': Die Verwechslung passiert wenn man sich Python Videos anschaut, und dann erst zu nem Buch greift. :roll: Aber theoretisch gesehen würde es mit: return aufgabe_generieren() dann klappen oder? Aber wenigstens weiß ich jetzt das Schleifen hier eher benutzt werden sollten. Ich änder das alles dann mal um :)

LG
BlackJack

@xhera: Praktisch wird das mit ``return aufgabe_generieren()`` klappen. Theoretisch könnte das zu einem `RuntimeError` führen wenn dabei zu oft die Division und Zahlen welche die Bedingung nicht erfüllen, gewählt werden.
Antworten