È più efficiente usare if-return-return o if-else-return?


141

Supponiamo che io abbia una ifdichiarazione con a return. Dal punto di vista dell'efficienza, dovrei usare

if(A > B):
    return A+1
return A-1

o

if(A > B):
    return A+1
else:
    return A-1

Dovrei preferire l'uno o l'altro quando uso un linguaggio compilato (C) o uno script (Python)?


11
In un linguaggio compilato non devi preoccuparti molto dell'efficienza. Il compilatore lo ordina. Dovresti scrivere il tuo codice in modo da poterlo leggere. (Devi ancora preoccuparti dell'efficienza dei tuoi algoritmi e l'uso sciatto dei tipi, ecc. Influirà sull'efficienza - semplicemente non ti preoccupi troppo del tuo stile.) Non so di Python.
AMS

5
Affidarsi al proprio compilatore per risolvere il proprio codice è un passaggio pericoloso e richiede un compilatore infallibile. Meglio se sai perché vuoi che il tuo codice faccia!
Andrew

1
Se quello che stai facendo è definito dalle specifiche, non credo che ci sia motivo di dubitare del compilatore. Sarà stato scritto per essere persone molto più intelligenti di te, ed è molto più probabile che tu abbia commesso un errore di loro.
sarà il

7
Come può essere chiuso per opinione? Potrebbe essere un'opinione dopo aver saputo che non vi è alcuna differenza di prestazioni tra i due. Non l'ho fatto e sono abbastanza sicuro che anche molte persone non lo abbiano fatto.
Jorge Leitao,

1
Sebbene la domanda sia piuttosto popolare, non è possibile rispondere in modo accurato senza una lingua specifica in mente, o altrimenti, rispondere per ogni lingua sarebbe troppo lungo per questo formato.
Emile Bergeron,

Risposte:


195

Poiché l' returnistruzione termina l'esecuzione della funzione corrente, le due forme sono equivalenti (sebbene la seconda sia probabilmente più leggibile della prima).

L'efficienza di entrambe le forme è comparabile, il codice macchina sottostante deve eseguire un salto se la ifcondizione è comunque falsa.

Nota che Python supporta una sintassi che ti consente di usare solo returnun'istruzione nel tuo caso:

return A+1 if A > B else A-1

32
C supporta anche questo. return (A>B)?A+1:A-1;Tuttavia non c'è assolutamente alcun guadagno in termini di prestazioni dalla scrittura del codice in questo modo. Tutto ciò che abbiamo ottenuto è rendere il codice offuscato, illeggibile e in alcuni casi più vulnerabile alle promozioni di tipo implicito.
Lundin

47
@Lundin offuscato? illeggibile? Solo per coloro che non conoscono l'operatore ternario.
glglgl

6
@Lundin Seguendo questa argomentazione, <è una cattiva pratica perché -1 < 1uproduce un risultato inaspettato.
glglgl

3
@glglgl: No, perché le persone si aspettano che l'operatore?: si comporti come if-else, il che non è vero. Se qualcuno scrivesse un codice simile -1 < 1u, che dubito, individuerebbe facilmente il bug. Molte persone scrivono comunque una versione del codice che ho pubblicato. Ho visto questi bug troppo spesso nel codice di produzione per fidarmi dell'operatore?:. Inoltre, come regola empirica, se la lingua ti offre due modi diversi di fare la stessa cosa, usa solo uno di essi, non sceglierne uno a caso a seconda del tuo umore.
Lundin,

6
@Lundin è un argomento con cui stare attenti?: In C, ma sembra che tu stia dicendo che si applica anche a Python. Puoi indicare qualche esempio in cui l'uso del ternario in Python porta a risultati inaspettati?
PVC

33

Dalla guida di stile di Chromium :

Non usare altro dopo il ritorno:

# Bad
if (foo)
  return 1
else
  return 2

# Good
if (foo)
  return 1
return 2

return 1 if foo else 2

1
Grazie. +1. Posso chiederti perché non usare altro dopo il ritorno?
Tim

1
if-else è funzionalmente equivalente, ma è dettagliato. L'altro non è necessario.
skeller88,

17
Sono rimasto sorpreso perché il primo sembra più chiaro e quindi migliore.
Tim

4
Puoi fare un caso ragionevole per entrambi. La cosa più importante in questa decisione dell'IMO è la coerenza all'interno della base di codice.
skeller88,

2
probabilmente troverai nella maggior parte dei casi che i if-else-returnrami non sono quasi mai uguali (se lo sono, allora dovresti comunque eseguire il refactoring; o usando un switchcostrutto o per Python, enumerando un dict / usando un callable / ecc.). Pertanto quasi tutti if-else-returnsono casi di clausole di guardia e quelli sono sempre testabili (deridono l'espressione testata) senza il else.
cowbert,

5

Per quanto riguarda lo stile di codifica:

La maggior parte degli standard di codifica, indipendentemente dalla lingua, vieta più dichiarazioni di ritorno da una singola funzione come cattiva pratica.

(Anche se personalmente direi che ci sono diversi casi in cui hanno più senso dichiarazioni di ritorno: parser di protocolli di testo / dati, funzioni con ampia gestione degli errori, ecc.)

Il consenso di tutti quegli standard di codifica del settore è che l'espressione dovrebbe essere scritta come:

int result;

if(A > B)
{
  result = A+1;
}
else
{
  result = A-1;
}
return result;

Per quanto riguarda l'efficienza:

L'esempio sopra e i due esempi nella domanda sono tutti completamente equivalenti in termini di efficienza. Il codice macchina in tutti questi casi deve confrontare A> B, quindi ramificare il calcolo A + 1 o A-1, quindi memorizzare il risultato in un registro CPU o nello stack.

MODIFICARE :

fonti:

  • MISRA-C: 2004 14.7, che a sua volta cita ...:
  • IEC 61508-3. Parte 3, tabella B.9.
  • IEC 61508-7. C.2.9.

37
Sei sicuro che la religione a ritorno singolo abbia infettato la maggior parte degli standard di codifica? Sarebbe spaventoso.
Daniel Fischer,

7
Direi che la regola non ha senso la maggior parte delle volte. Tendo a trovare il codice più leggibile e più facile da seguire con i ritorni nei punti appropriati. Ma sono solo io. Tuttavia, ho pensato agli standard di codifica per azienda / progetto, non a cose come MISRA dove altrimenti le prescrizioni idiote possono occasionalmente avere qualche merito. Spero che la maggior parte non abbia accettato l'idea del singolo punto di uscita.
Daniel Fischer,

3
@DanielFischer: nello standard di codifica C basato su MISRA che ho progettato per la mia azienda, ho la regola "Una funzione deve avere un solo punto di uscita, alla fine della funzione, a meno che un singolo punto di uscita non faccia il codice meno leggibile ". Quindi è MISRA-C ma con un'eccezione alla regola. Se si scrive una funzione di analisi avanzata che può restituire diciamo 10 errori diversi, il livello di parentesi graffe nidificate rende il codice completamente illeggibile - in tal caso sarebbe più sensato restituire immediatamente quando si verifica un errore.
Lundin

6
Vedere questa domanda SO per una discussione e ulteriori collegamenti ad ulteriori discussioni sulla questione del punto di uscita singolo. Oltre al fatto che la regola del punto di uscita singolo è vecchio stile e eccessivamente "ingegneristica", Python promuove specificamente una vista "piatta è meglio di nidificata" , e mettere return ovunque ciò che risulta essere chiaro è il modo idiomatico di farlo in Python.
John Y,

1
@percebus Sono completamente d'accordo e la complessità ciclomatica è un buon argomento contro il singolo ritorno. E ho cercato diverse volte il comitato MISRA su questo, per esempio vedere questo . Almeno la regola è stata declassata a consulenza in MISRA-C: 2012.
Lundin,

3

Con qualsiasi compilatore sensibile, non dovresti osservare alcuna differenza; dovrebbero essere compilati con codice macchina identico in quanto equivalenti.


2

Questa è una questione di stile (o preferenza) poiché l'interprete non se ne cura. Personalmente proverei a non fare la dichiarazione finale di una funzione che restituisce un valore a un livello di rientro diverso dalla base delle funzioni. L'altro nell'esempio 1 oscura, anche se solo leggermente, dove si trova la fine della funzione.

Per preferenza utilizzo:

return A+1 if (A > B) else A-1

Poiché obbedisce sia alla buona convenzione di avere una singola dichiarazione di ritorno come ultima affermazione nella funzione (come già accennato) sia al buon paradigma di programmazione funzionale di evitare risultati intermedi di stile imperativo.

Per funzioni più complesse preferisco suddividere la funzione in più sotto-funzioni per evitare ritorni prematuri, se possibile. Altrimenti torno a usare una variabile di stile imperativa chiamata rval. Cerco di non usare più dichiarazioni di ritorno a meno che la funzione non sia banale o che la dichiarazione di ritorno prima della fine sia il risultato di un errore. Il ritorno prematuro evidenzia il fatto che non è possibile continuare. Per funzioni complesse progettate per ramificarsi in più funzioni secondarie, provo a codificarle come istruzioni di caso (guidate da un dict per esempio).

Alcuni poster hanno menzionato la velocità di funzionamento. La velocità di runtime è secondaria per me poiché se hai bisogno di velocità di esecuzione Python non è il linguaggio migliore da usare. Uso Python per quanto riguarda l'efficienza della codifica (ovvero la scrittura di codice privo di errori) che conta per me.


1
Se un utente voterà in negativo la mia risposta, apprezzerei un commento sul perché pensavano che mi sbagliassi.
Stephen Ellwood,

Probabilmente vorrei solo una riga prima di renderla 1 riga per istruzione a fini di leggibilità. var n = 1 if (A > B) else -1 return A+n
percebus,

@percebus in alcuni casi concordo sul fatto che il nome della variabile possa migliorare il significato. Ad esempio: "code" move_x = 1 se my_x <avversario_x altro -1 # si sposta verso l'avversario
Stephen Ellwood,

A proposito, ho effettivamente votato la tua risposta. Se vedi che la mia risposta è piuttosto simile
percebus il

2

Personalmente evito elseblocchi quando possibile. Vedi la campagna Anti-if

Inoltre, non fanno pagare "extra" per la linea, sai: p

"Semplice è meglio di complesso" & "La leggibilità è re"

delta = 1 if (A > B) else -1
return A + delta

2
Perché il voto negativo? È una risposta "pitonica". Potresti non considerarlo una risposta preferita. Ma non è invalido. Sto anche seguendo il Principio KISS en.wikipedia.org/wiki/KISS_principle
percebus

3
Ho valutato la tua risposta poiché per me segna sulla leggibilità e sulla semplicità. Personalmente trovo offensivo il fatto che qualcuno mi sottovaluti senza istruirmi sul perché la mia risposta sia attivamente negativa.
Stephen Ellwood,

1
Non ho mai sentito parlare della campagna Anti-if, ma posso capire perché ifs può essere pericoloso. Cerco sempre di limitare la quantità di codice racchiusa da un'istruzione if e di riscrivere gli alberi elif per usare dict. Questo però sta diventando un po 'fuori tema.
Stephen Ellwood,

1
@StephenEllwood Usare dicts per evitare differenze è una pessima idea dal punto di vista delle prestazioni.
Bachsau,

@Bachsau Probabilmente hai ragione. Non ho mai dovuto preoccuparmi delle prestazioni poiché tutti i miei script vengono eseguiti in pochi secondi. Per me la leggibilità di solito supera le prestazioni. Dal momento che non sono un programmatore a tempo pieno; sono solo un mezzo per raggiungere un fine.
Stephen Ellwood,

1

La versione A è più semplice ed è per questo che la userei.

E se attivi tutti gli avvisi del compilatore in Java riceverai un avviso sulla seconda versione perché è inutile e aumenta la complessità del codice.


1

So che la domanda è taggata in pitone, ma menziona linguaggi dinamici, quindi ho pensato che dovrei menzionare che in ruby ​​l'istruzione if ha effettivamente un tipo di ritorno in modo da poter fare qualcosa di simile

def foo
  rv = if (A > B)
         A+1
       else
         A-1
       end
  return rv 
end

O perché ha anche un ritorno implicito semplicemente

def foo 
  if (A>B)
    A+1
  else 
    A-1
  end
end

che aggira il problema di stile di non avere più ritorni abbastanza bene.

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.