Quale stile utilizzare per i parametri di ritorno inutilizzati in una chiamata di funzione Python


30

Esiste uno stile di codifica consigliato / generalmente accettato per la gestione di situazioni in cui una funzione restituisce una tupla di valori ma solo uno di questi valori viene utilizzato in seguito (si noti che questo è principalmente destinato a funzioni di libreria che non posso cambiare - scrivere un wrapper in giro la chiamata è probabilmente un po 'eccessiva ...)? Invece di farlo

a, b, c = foo()

e quindi non usare be c, quale delle seguenti varianti dovrebbe essere preferita (o ce n'è un'altra?):

Variante 1 (trattino basso)

a, _, _ = foo()

(che è molto chiaro e semplice ma potrebbe scontrarsi con _ = gettext.gettextutilizzato in molte applicazioni che usano la traduzione)

Variante 2 (nome fittizio)

a, unused, unused = foo()

(non molto attraente, penso, lo stesso vale per altri nomi come dummy)

Variante 3 (indice)

a = foo()[0]

(per me l' ()[0]aspetto non-pitonico ...)


Contrariamente alla mia precedente risposta, cosa succede con la variante 3 quando si desidera ora fare riferimento a 2/3 dei valori restituiti? Ho rimosso la mia risposta perché mi sono reso conto che non sapevo abbastanza su Python per giustificarlo.
Craige,

@Craige: non ho visto la tua risposta prima di averla rimossa ... Stai chiedendo se a, b = foo()[0:2]funzionerebbe? Se sì: sì, sì :)
user49643

Era esattamente quello che stavo chiedendo. Se funziona (come hai detto tu), utilizzerei la variante 3. Reinstallo la mia risposta data queste informazioni.
Craige

3
Per inciso, in questi giorni è possibile utilizzare la sintassi piuttosto bella per il disimballaggio 'esteso' : a, *_ = foo()eliminerà tutti i valori tranne il primo.
Benjamin Hodgson,

Risposte:


17

L'uso del carattere di sottolineatura per variabili non utilizzate è sicuramente accettabile. Attenzione però, in alcune basi di codice non è un'opzione poiché quell'identificatore è riservato come scorciatoia gettext. Questa è l'obiezione più frequente a questo stile (anche se non è un problema per la maggioranza per quanto posso giudicare). Lo consiglierei comunque e lo userò sempre da solo.

I nomi mi piacciono dummyo unusedtendono a irritarmi personalmente, e non li vedo molto spesso (in Python, cioè: conosco una base di codice Delphi che usa dummyliberamente, ed è anche trapelata negli script associati al programma in questione). Ti sconsiglio.

Anche l'estrazione di un elemento dalla tupla restituita va bene. Inoltre, risparmia un po 'di seccatura nell'ottenere giusto il numero di valori non utilizzati. Nota però che ha due potenziali aspetti negativi:

  • Non esplode se il numero di valori è diverso da quello che ti aspetti. Questo può essere utile per rilevare confusione e errori di battitura.
  • Funziona solo quando il valore restituito è una sequenza (principalmente tuple ed elenchi, ma restiamo generici). Di persona, conosco una classe nel mio codice (un vettore 2D) che è iterabile e produce un numero costante di valori (e quindi può essere usato per disimballare le assegnazioni), ma non è indicizzabile.

Ho fatto in realtà parlare di gettext nella mia interrogazione :) Comunque, ho accettato la tua risposta - sembra che non v'è alcuna chiara unico stile accettata, ma la risposta sollevato alcuni punti interessanti.
user49643

Per evitare problemi con gettext (o per evitare problemi simili nell'interprete) puoi usare i trattini bassi (detti anche dunders) invece del singolo.
Zim,

21

Pylint mi ha preso l'abitudine di farlo in questo modo:

widget, _parent, _children = f()

Cioè, i risultati non utilizzati hanno un nome descrittivo preceduto da _. Pylint considera i locali con il prefisso _ come inutilizzati e i globali o gli attributi con il prefisso _ come privati.


3

Se nell'intero progetto lo stai facendo solo una volta o raramente scrivo la funzione particolare, userei la variante 1 se sai che gettextnon è un problema in quel modulo, e altrimenti la variante 3.

D'altra parte, se lo facessi molto - e specialmente se ogni volta che desideri un sottoinsieme diverso dei valori di ritorno (facendo un wrapper per restituire quelli che ti interessano non fattibili), potrebbe essere utile scrivere un wrapper che mette i risultati in una tupla denominata o in un'istanza di qualche altra classe descrittiva, che ti consentirebbe di fare:

bar = foo()

E poi lavora con bar.a, bar.be bar.c.


2

Come altri hanno già detto, underscore ( _) è lo standard. Ma se il carattere di sottolineatura viene utilizzato per le traduzioni, penso che il doppio trattino basso sia la migliore alternativa.

var, __, value = "VAR=value".partition('=')

Meglio di questi:

var, unused, value = "VAR=value".partition('=')

var, unused_del, value = "VAR=value".partition('=')

var, _del, value = "VAR=value".partition('=')


1

Sono un programmatore non Python, ma per me la terza variante ha più senso.

Nella variante 3 sei assolutamente chiaro con quali valori sei interessato a trattare. Nelle varianti 1 e 2, i valori vengono riassegnati alle variabili e pertanto possono essere utilizzati. Potresti averli nominati in modo oscuro, ma una cattiva denominazione non è in realtà una soluzione a nessun problema.

A parte la chiarezza, perché dovresti voler assegnare valori non utilizzati a uno slot in memoria (come nelle varianti 1 e 2)? Questa sarebbe una soluzione scadente in termini di gestione della memoria.


Se lo metti sempre sulla stessa variabile, il problema di memoria non sarebbe solo la dimensione di una singola variabile in un dato momento? Non penso che dovrebbe essere un problema.
Michael McQuade,

-2

Ecco una regola generale: se viene utilizzato solo 1 dei valori restituiti, perché non semplicemente restituire quel valore 1? Nel caso in cui il flag venga chiamato da più posizioni, mantenere un flag per lo stesso e restituire i valori secondo il flag.

MODIFICARE:

Nel caso in cui mi trovassi nella tua situazione e non avessi scritto la funzione, forse sceglierei la variante 2. Conserverei lì i nomi fittizi in modo che i parametri possano essere utilizzati in caso di necessità. Affettare un elenco avrà un piccolo sovraccarico. Forse puoi risparmiare qualche byte per ricevere i dati indesiderati.


-1 Suppongo che non abbia definito la funzione e quindi non possa cambiare ciò che restituisce. Penso che si riferisca a quando la funzione restituisce 3 valori, ma si preoccupa solo di 1 nel suo caso d'uso corrente.
Craige,

@Craige: Sì, intendevo funzioni che non potevo cambiare - ho aggiunto una nota alla mia domanda chiarendola.
user49643

Sei sicuro dell'overhead? Ho provato un test ipython molto semplice: %timeit a, _, _ = foo()rispetto al %timeit a = foo()[0]risultato di 123 ns rispetto a 109 ns, ovvero l'affettamento sembra essere effettivamente più veloce del valore di decompressione. O avevi in ​​mente una situazione specifica?
user49643

2
Un altro scenario plausibile è che non sono necessari tutti i valori per alcune chiamate.
Keith Thompson,
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.