return-Anweisung gibt immer 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
ki
User
Beiträge: 5
Registriert: Samstag 8. November 2008, 16:25
Kontaktdaten:

Samstag 8. November 2008, 16:44

Hallo liebes Forum,

ich bin neu hier und habe gleich mal eine Frage zu meinem kleinen Script, das ich hier mal poste:

Code: Alles auswählen


f = ''

def factors(n, i):
    global f
    if i == 0:
        print f
        return f
    elif n % i > 0:
        factors(n, i-1)
    else:        
        f = str(i) + " " + f
        factors(n, i-1)

print factors( int( raw_input('N eingeben: ') ), int( raw_input('i eingeben: ') ) )
Also, Wenn ich z. B. für N und i jeweils 10 eingebe, komt folgende Meldung zurück:

N eingeben: 10
i eingeben: 10

1 2 5 10
None
Hat jemand eine Ahnung, wodran das liegen kann? Über print funktioniert die Rückgabe ja ...

Danke für Eure Hilfe!

Ki
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

Samstag 8. November 2008, 16:55

In Python hat jede Funktion einen Rückgabewert. Wenn du nicht explizit via return einen Wert zurückgibst, dann ist es None.

In deinem Fall tritt das ein, wenn der "else"-Teil abgearbeitet wird und zu Ende ist.
ki
User
Beiträge: 5
Registriert: Samstag 8. November 2008, 16:25
Kontaktdaten:

Samstag 8. November 2008, 20:07

Hmm, aber er kann ja nicht nach dem else Teil raus, da dann die funktion factors erneut aufgerufen wird. Die rekursive Schleife wird ja nur bei der if == true Abfrage verlassen. Und hier gibt das Skript ja über den print-Befehl korrekt den Wert von f aus, allerdings wird über die return-Anweisung None zurückgegeben.

Das verstehe ich halt nicht
Pekh
User
Beiträge: 482
Registriert: Donnerstag 22. Mai 2008, 09:09

Samstag 8. November 2008, 20:12

Wenn eine Funktion nicht über ein explizites 'return' beendet wird ergänzt der Interpreter ein implizites 'return None'. Und das ist bei dir nach dem Abarbeiten des 'else'-Zweiges der Fall.

Edit: Und auch nach dem 'elif'. Einfach weil du das Ergebnis der rekursiven Aufrufe von factors nicht weiter hochreichst. Schreibe mal sowohl im 'elif'-Zweig als auch im 'else'-Teil ein 'return' vor den Funktionsaufruf. Das sollte dieses Problem beheben.

Edit2: Und warum gehst du über 'global', wenn du doch ohnehin schon mit Parametern arbeitest? Das schreit doch geradezu nach irgendwelchen unbeabsichtigten Seiteneffekten.
ki
User
Beiträge: 5
Registriert: Samstag 8. November 2008, 16:25
Kontaktdaten:

Samstag 8. November 2008, 20:24

Aber die funktion wird ja in der if Abfrage durch ein explizites return beendet

edit: sorry, habe erst danach deine edits gelesen
ki
User
Beiträge: 5
Registriert: Samstag 8. November 2008, 16:25
Kontaktdaten:

Samstag 8. November 2008, 20:34

wenn ich f nicht global setze, bekomme ich folgende Fehlermeldung:
f = str(i) + " " + f
UnboundLocalError: local variable 'f' referenced before assignment
Das ist nun mein aktueller Code:

Code: Alles auswählen

f = ''

def factors(n, i):
    #global f
    if i == 0:
        return f
    elif n % i > 0:
        factors(n, i-1)
        return f
    else:        
        f = str(i) + " " + f
        factors(n, i-1)
        return f

print factors( int( raw_input('\nN eingeben: ') ), int( raw_input('i eingeben: ') ) )
Das Problem ist, wenn ich f nicht ausserhalb der funktion definiere, bekome ich die Meldung, das ich versuche eine unbekannte Variable in der Zuweisung zu verwenden.

Wenn ich aber f in jeder neuen Instanz von der Funktion mittels f = "" neu definiere, kann ich ja nicht meinen Ausgabe-String über die Instanzen zusammensetzen.

Hat jemand einen alternativen Vorschlag?

edit: ach ja, durch die returns ist nun das Problem gelöst, das None zurückgegeben wurde
Pekh
User
Beiträge: 482
Registriert: Donnerstag 22. Mai 2008, 09:09

Samstag 8. November 2008, 20:36

Der in meinen Augen schönere Ansatz ohne das allgemein verpönte 'global':

Code: Alles auswählen

def factors(n, i, f=''):
    if i == 0:
        print f
        return f
    elif n % i > 0:
        return factors(n, i-1, f)
    else:
        return factors(n, i-1, f) + ' %d' % i
ki
User
Beiträge: 5
Registriert: Samstag 8. November 2008, 16:25
Kontaktdaten:

Samstag 8. November 2008, 20:52

Das ist allerdings schön!

Gefällt mir gut mit dem return die funktion erneut aufzurufen

Danke für die Hilfe!
DasIch
User
Beiträge: 2450
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Samstag 8. November 2008, 21:02

Du gibst mit return den Wert zurück, den die wiederaufgerufene Funktion zurückgibt. Wenn dir dass klar ist weisst du auch wieso du vorher None bekommen hast.
yipyip
User
Beiträge: 418
Registriert: Samstag 12. Juli 2008, 01:18

Montag 10. November 2008, 19:36

Das 'f' wird doch eigentlich gar nicht gebraucht.
Und eine Liste als Datenstruktur halte ich auch für sinnvoller.

Code: Alles auswählen

def factors(n, i):
    
  if i <= 0:
    return []

  return factors(n, i-1) + ([], [i])[not n % i]
@ki
Dir schwebte (vermutlich etwas vage) das Konzept
eines Akkumulators vor Augen,
daher 2 Variationen zu diesem Thema:

Code: Alles auswählen

def factors2(n, i, acc=[]):
  
  if i <= 0:
    return acc

  return factors2(n, i-1, (acc, acc + [i])[not n % i])

####

def factors3(n, i, acc=None):
  
  if acc == None:
    acc = []
    
  if i <= 0:
    return acc

  if not n % i:
    acc.append(i)

  return factors3(n, i-1, acc)

:wink:
yipyip
Antworten