return, return None e nessun ritorno a tutti?


386

Considera tre funzioni:

def my_func1():
  print "Hello World"
  return None

def my_func2():
  print "Hello World"
  return

def my_func3():
  print "Hello World"

Sembrano tutti restituire Nessuno. Ci sono differenze tra il comportamento del valore restituito di queste funzioni? Ci sono dei motivi per preferire l'uno rispetto all'altro?


40
Nota che c'è una differenza stilistica. return Noneimplica per me che la funzione a volte ha un Nonevalore di non ritorno, ma nella posizione di return Nonenon esiste tale valore di ritorno. Scrivere no returnimplica per me non c'è mai un valore di ritorno interessante, un po 'come una "procedura" al contrario di una "funzione". returnimplica di esistere presto da una "procedura" come da punto precedente.

Risposte:


500

Sul comportamento reale, non c'è differenza. Tornano tutti Nonee basta. Tuttavia, c'è un tempo e un luogo per tutti questi. Le seguenti istruzioni sono fondamentalmente come dovrebbero essere usati i diversi metodi (o almeno come mi è stato insegnato che dovrebbero essere usati), ma non sono regole assolute, quindi puoi mescolarli se ti senti necessario.

utilizzando return None

Questo dice che la funzione è effettivamente destinata a restituire un valore per un uso successivo, e in questo caso restituisce None. Questo valore Nonepuò quindi essere utilizzato altrove. return Nonenon viene mai utilizzato se non ci sono altri valori di ritorno possibili dalla funzione.

Nel seguente esempio, torniamo person's motherse la persondata è un essere umano. Se non è un essere umano, torniamo Nonedal momento personche non ha un mother(supponiamo che non sia un animale o qualcosa del genere).

def get_mother(person):
    if is_human(person):
        return person.mother
    else:
        return None

utilizzando return

Questo è usato per lo stesso motivo dei breakloop. Il valore restituito non ha importanza e vuoi solo uscire dall'intera funzione. È estremamente utile in alcuni luoghi, anche se non ne hai bisogno così spesso.

prisonersNe abbiamo 15 e sappiamo che uno di loro ha un coltello. Esaminiamo ciascuno prisonerper uno per verificare se hanno un coltello. Se colpiamo la persona con un coltello, possiamo semplicemente uscire dalla funzione perché sappiamo che c'è solo un coltello e nessun motivo per il resto prisoners. Se non lo troviamo prisonercon un coltello, lanciamo un avviso. Questo potrebbe essere fatto in molti modi diversi e l'utilizzo returnprobabilmente non è nemmeno il modo migliore, ma è solo un esempio per mostrare come usare returnper uscire da una funzione.

def find_prisoner_with_knife(prisoners):
    for prisoner in prisoners:
        if "knife" in prisoner.items:
            prisoner.move_to_inquisition()
            return # no need to check rest of the prisoners nor raise an alert
    raise_alert()

Nota: non dovresti mai farlo var = find_prisoner_with_knife(), poiché il valore restituito non è pensato per essere catturato.

Non usare returnaffatto

Anche questo restituirà None, ma quel valore non è pensato per essere usato o catturato. Significa semplicemente che la funzione è terminata correttamente. E 'fondamentalmente lo stesso come returnin voidfunzioni in linguaggi come C ++ o Java.

Nel seguente esempio, impostiamo il nome della madre della persona e quindi la funzione termina dopo il completamento con esito positivo.

def set_mother(person, mother):
    if is_human(person):
        person.mother = mother

Nota: non dovresti mai farlo var = set_mother(my_person, my_mother), poiché il valore restituito non è pensato per essere catturato.


5
var = get_mother()va bene se stai passando varad altre funzioni che accettano None- "mai" è un po 'estremo
joelb

Come si dovrebbe accettare il valore restituito se var = get_mother()non può essere utilizzato? IMHO va benissimo farlo. Devi solo assicurarti di controllare un Nonevalore non con if varprima di usarlo.
winklerrr,

Ho pensato che fosse importante menzionare che questa non è solo una buona convenzione, è richiesta dal PEP8. Pubblico una risposta per complimentarmi con la tua e citare PEP8 su questo.
Fabiano,

29

Sì, sono tutti uguali.

Possiamo rivedere il codice macchina interpretato per confermare che stanno facendo esattamente la stessa cosa.

import dis

def f1():
  print "Hello World"
  return None

def f2():
  print "Hello World"
  return

def f3():
  print "Hello World"

dis.dis(f1)
    4   0 LOAD_CONST    1 ('Hello World')
        3 PRINT_ITEM
        4 PRINT_NEWLINE

    5   5 LOAD_CONST    0 (None)
        8 RETURN_VALUE

dis.dis(f2)
    9   0 LOAD_CONST    1 ('Hello World')
        3 PRINT_ITEM
        4 PRINT_NEWLINE

    10  5 LOAD_CONST    0 (None)
        8 RETURN_VALUE

dis.dis(f3)
    14  0 LOAD_CONST    1 ('Hello World')
        3 PRINT_ITEM
        4 PRINT_NEWLINE            
        5 LOAD_CONST    0 (None)
        8 RETURN_VALUE      

4
attenzione qui ... dis.disritorna None: -X
mgilson

L'unico modo per ottenere l'output di dis come stringa è reindirizzare lo stdout a una sorta di buffer IO (ad es. StringIO). Anche allora, il confronto diretto in quel modo potrebbe non funzionare poiché credo che dis.disriporta anche alcuni numeri di riga ...
mgilson

È irrilevante che stiano usando o meno gli stessi identici registri, quindi ho cambiato il mio codice in modo che ora guardiamo semplicemente il codice della macchina invece di fare una sorta di paragone di stringhe sciocche. Grazie per l'heads molto grande.
David Marx,

19

Ognuno di essi restituisce lo stesso singleton None- Non c'è differenza funzionale.

Penso che sia ragionevolmente idiomatico tralasciare l' returnaffermazione a meno che non sia necessario che esca anticipatamente dalla funzione (nel qual caso un nudo returnè più comune) o restituisce qualcosa di diverso None. Ha anche senso e sembra essere idiomatico scrivere return Nonequando è in una funzione che ha un altro percorso che restituisce qualcosa di diverso None. Scrivere return Noneesplicitamente è un segnale visivo per il lettore che esiste un altro ramo che restituisce qualcosa di più interessante (e che probabilmente il codice chiamante dovrà gestire entrambi i tipi di valori restituiti).

Spesso in Python, le funzioni che restituiscono Nonesono usate come le voidfunzioni in C - Il loro scopo è generalmente quello di operare sugli argomenti di input in atto (a meno che non si utilizzino dati globali ( shudder )). Il ritorno di Nonesolito rende più esplicito che gli argomenti sono stati mutati. Ciò rende un po 'più chiaro il motivo per cui ha senso lasciare la returnfrase dal punto di vista delle "convenzioni linguistiche".

Detto questo, se stai lavorando in una base di codice che ha già convenzioni preimpostate su queste cose, seguirò sicuramente l'esempio per aiutare la base di codice a rimanere uniforme ...


1
O più in generale, ogni volta che una funzione termina senza colpire returnun'istruzione, ritorna None.

Non è idiomatico omettere l'istruzione return se la funzione dovrebbe restituire un valore. Solo le funzioni che operano esclusivamente tramite effetti collaterali devono omettere la dichiarazione di ritorno.
molecola

@molecule - Sì, penso che forse non ho fatto il miglior lavoro nella mia spiegazione qui. Ho provato ad aggiornarlo senza renderlo un clone completo della risposta (molto migliore) sopra. Non sono ancora molto contento di questo post ... Parte di me vuole cancellarlo (poiché la risposta sopra è molto meglio) e parte di me vuole mantenerlo - 9 persone finora hanno pensato che fosse buono per una ragione o l'altra. Forse ho colpito qualcosa che qualcun altro ha mancato?
mgilson,

1
@ZAB - Non credo sia possibile. In Python posso scimmiettare qualsiasi cosa con qualsiasi cosa (questo è di progettazione ed è una grande caratteristica se usato con parsimonia). In particolare, posso applicare una patch a una scimmia che ha un ritorno con una che non lo fa. Tutti i controlli "non un'espressione" avvengono al momento dell'analisi, ma a causa del patching delle scimmie, ciò non può avvenire fino al runtime. IOW, è completamente diverso. Personalmente, penso che l'attuale comportamento sia abbastanza ragionevole (e coerente con altre lingue di alto livello), ma non sono quello che devi convincere :-).
mgilson,

1
@ZAB - entrambi Rubye Javascriptadottano lo stesso approccio di Python. Sono sicuro che ci sono esempi di linguaggi di alto livello che dicono "void" nell'espressione, ma al momento non riesco a pensare a nessuno (forse se si considera Javaun linguaggio di alto livello) ... Come sarebbe il patching delle scimmie una funzione (che è utile per deridere nei test tra le altre cose) funziona in un mondo ipotetico in cui Python ha una voidparola chiave che l'ha resa così la funzione non ha restituito nulla? (Inoltre, come ho detto prima, non è necessario convincermi che questo è un cattivo design. Non posso fare nulla anche se hai ragione)
mgilson

4

Come altri hanno risposto, il risultato è esattamente lo stesso, Noneviene restituito in tutti i casi.

La differenza è stilistica, ma tieni presente che PEP8 richiede che l'uso sia coerente:

Sii coerente nelle dichiarazioni di reso. O tutte le istruzioni di ritorno in una funzione dovrebbero restituire un'espressione o nessuna di esse dovrebbe. Se una dichiarazione di ritorno restituisce un'espressione, tutte le dichiarazioni di ritorno in cui non viene restituito alcun valore devono dichiararlo esplicitamente come ritorno Nessuno e una dichiarazione di ritorno esplicita deve essere presente alla fine della funzione (se raggiungibile).

Sì:

def foo(x):
    if x >= 0:
        return math.sqrt(x)
    else:
        return None

def bar(x):
    if x < 0:
        return None
    return math.sqrt(x)

No:

def foo(x):
    if x >= 0:
        return math.sqrt(x)

def bar(x):
    if x < 0:
        return
    return math.sqrt(x)

https://www.python.org/dev/peps/pep-0008/#programming-recommendations


Fondamentalmente, se mai si restituisce un Nonevalore non valido in una funzione, significa che il valore restituito ha un significato e deve essere intercettato dai chiamanti. Quindi quando ritorni None, deve anche essere esplicito, trasmettere Nonein questo caso ha un significato, è uno dei possibili valori di ritorno.

Se non hai bisogno di tornare, la funzione funziona sostanzialmente come una procedura anziché come una funzione, quindi non includere l' returnistruzione.

Se stai scrivendo una funzione simile a una procedura e c'è un'opportunità per tornare prima (cioè hai già finito a quel punto e non hai bisogno di eseguire il resto della funzione) puoi usare una returns vuota per segnalare al lettore è solo una finitura anticipata dell'esecuzione e il Nonevalore restituito implicitamente non ha alcun significato e non è destinato a essere intercettato (la funzione simile a una procedura restituisce sempre Nonecomunque).


3

In termini di funzionalità questi sono tutti uguali, la differenza tra loro è nella leggibilità del codice e nello stile (che è importante considerare)

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.