2009-05-03 12 views
19

Voglio refactoring una grande funzione Python in quelle più piccole. Ad esempio, si consideri questo frammento di codice seguente:Python: evitare gli avvertimenti di pylint su troppi argomenti

x = x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 

Naturalmente, questo è un esempio banale. In pratica, il codice è più complesso. Il mio punto è che contiene molte variabili local-scope che avrebbero dovuto essere passati alla funzione estratto, che potrebbe apparire come:

def mysum(x1, x2, x3, x4, x5, x6, x7, x8, x9): 
    x = x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 
    return x 

Il problema è che pylint innescherebbe un avvertimento circa troppi argomenti. ho potuto evitare l'avvertimento facendo qualcosa di simile:

def mysum(d): 
    x1 = d['x1'] 
    x2 = d['x2'] 
    ... 
    x9 = d['x9'] 
    x = x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 
    return x 

def mybigfunction(): 
    ... 
    d = {} 
    d['x1'] = x1 
    ... 
    d['x9'] = x9 
    x = mysum(d) 

ma questo approccio Loos brutto per me, richiede la scrittura di un sacco di codice che è anche ridondante.

Esiste un modo migliore per farlo?

+1

Credo che mysum() possa essere semplificato in: 'return sum (d.values ​​())' o almeno 'return sum ([d [foo] per foo in (' x1 ',' x2 ', .. ., 'x9')]) '. Sono troppo felice nella comprensione delle liste? – MatrixFrog

+1

mysum() è solo un'astrazione, in scenari reali il codice che deve essere estratto è molto più complesso. Il mio punto è di dover passare molte variabili alla funzione estratta ed evitare l'avvertimento di pilore se possibile (senza fare esplicitamente ricorso a pylint per ignorare tale avviso). – Anonymous

risposta

5

Semplifica o interrompe la funzione in modo che non richieda nove argomenti (o ignori il puntatore, ma gli schivati ​​come quelli che stai proponendo vanificano lo scopo di uno strumento sfilaccia).

EDIT: se si tratta di una misura temporanea, disattivare l'avviso per la particolare funzione in questione con un commento come descritto qui: http://lists.logilab.org/pipermail/python-projects/2006-April/000664.html

Successivamente, è possibile grep per tutte le avvertenze disabili.

+0

Il mio obiettivo è prima di rompere la grande funzione. Quindi potrei procedere per rompere ulteriormente le parti più piccole. Ma voglio evitare questo avvertimento specifico del pilastro durante il processo di refactoring, se questo è possibile. – Anonymous

12

Si potrebbe provare a utilizzare Python's variable arguments funzione:

def myfunction(*args): 
    for x in args: 
     # Do stuff with specific argument here 
+1

È come usare un elenco, vedi sotto. – Anonymous

6

Forse si potrebbe trasformare alcuni degli argomenti in variabili membro. Se hai bisogno di quello stato, una classe mi sembra una buona idea.

+0

Non funziona se ho bisogno di rifattorizzare un metodo di classe e le variabili passate sono locali al metodo big refactored e non sono usate nell'intera classe. – Anonymous

+3

No, ma se si estrae un nuovo tipo, potrebbe essere possibile trasformare parte dello stato in variabili membro. –

0

Python dispone di alcuni strumenti di programmazione funzionale che sono adatti alle vostre esigenze. Controlla lambda functions e map. Inoltre, stai usando dicts quando sembra che tu possa essere servito molto meglio con le liste. Per il semplice esempio che hai fornito, prova questo idioma. Si noti che la mappa sarebbe meglio e più velocemente, ma non può soddisfare le vostre esigenze:

def mysum(d): 
    s = 0 
    for x in d: 
     s += x 
    return s 

def mybigfunction(): 
    d = (x1, x2, x3, x4, x5, x6, x7, x8, x9) 
    return mysum(d) 

Lei ha parlato di avere un sacco di variabili locali, ma francamente se hai a che fare con le liste (o tuple), è necessario utilizzare gli elenchi e eliminare tutte quelle variabili locali nel lungo periodo.

+0

Non riesco a usare una lista. Nel mio banale esempio le mie variabili passate hanno lo stesso ruolo. Ma in uno scenario complesso le variabili hanno significati diversi, quindi sostituire i loro nomi (che portano un significato logico) con gli elementi di elenco a cui accede l'indice distruggerebbe totalmente la leggibilità del codice. – Anonymous

+2

Dovrai usare il comando allora. Detto questo, non sarai in grado di ripulire molte cose a meno che tu non modifichi alcune delle tue esigenze. In alternativa è possibile definire una classe per tutte queste cose e quindi inserire la logica in vari metodi di classe. probabilmente più pulito di un massiccio albero if-based basato su un dict, almeno! – easel

55

In primo luogo, una delle Perlis's epigrams:

"Se si dispone di una procedura con 10 parametri, probabilmente perso un po '."

Alcuni dei 10 argomenti sono presumibilmente correlati. Raggruppali in un oggetto e passa quello.

Fare un esempio su, perché non c'è abbastanza informazioni nella domanda a cui rispondere direttamente:

class PersonInfo(object): 
    def __init__(self, name, age, iq): 
    self.name = name 
    self.age = age 
    self.iq = iq 

Allora la vostra funzione 10 argomento:

def f(x1, x2, name, x3, iq, x4, age, x5, x6, x7): 
    ... 

diventa:

def f(personinfo, x1, x2, x3, x4, x5, x6, x7): 
    ... 

e il chiamante cambia in:

personinfo = PersonInfo(name, age, iq) 
result = f(personinfo, x1, x2, x3, x4, x5, x6, x7) 
+3

Mi piace questa risposta perché indica come pensare al problema! –

24

Vuoi un modo migliore per passare gli argomenti o solo un modo per impedire a pylint di darti dei problemi? In quest'ultimo caso, mi sembra di ricordare che si potrebbe fermare il fastidioso mettendo pylint commenti -controlling nel codice lungo le linee di:

#pylint: disable-msg=R0913 

o:

#pylint: disable-msg=too-many-arguments 

ricordando di riattivarli il prima possibile.

A mio parere, non c'è niente di intrinsecamente sbagliato con il superamento di un sacco di argomenti e soluzioni che sostengono tutti avvolgendolo in qualche argomento contenitore in realtà non risolvere eventuali problemi, altro che fermarsi pylint da voi :-) fastidioso.

Se è necessario passare venti argomenti, quindi passarli. Può essere che questo sia richiesto perché la tua funzione sta facendo troppo e un ri-factoring potrebbe aiutarti, ed è qualcosa che dovresti guardare. Ma non è una decisione che possiamo fare a a meno che non vediamo quale sia il codice "reale".

+3

Questa risposta incoraggia davvero cattive abitudini - di leggere la società nel 2015. 1) Disabilitazione dei controlli con il loro numero - versioni pylint moderni supportano descrittori simbolici, molto più esplicativo 2) disattivando qualcosa dovrebbe avere anche un commento con una spiegazione di la ragione perché viene disattivato 3) ci dovrebbe essere solo una direttiva per riga, bilanciata da una corrispondente riattivazione 4) Solitamente pylint non avere un punto. Il codice che si scontra con questi limiti è probabilmente illeggibile/non mantenibile. 5) Piuttosto che passare un diluvio di parametri, è molto meglio usare un dizionario o una tupla con nome. –

+3

Igor, ecco perché ho detto "sulla falsariga di". Con tutti i mezzi usare simbolici piuttosto che numeri, o uno per riga, o commentare perché, o riattivare (anche se dovresti considerare cosa significhi se fosse stato disabilitato in precedenza - meglio sarebbe un metodo per salvare/disabilitare/ripristinare).Niente di tutto ciò cambia l'utilità della risposta stessa, che è dire a Pylint di smettere di avvertire su un problema che l'utente non sa di sapere (e accetta le conseguenze). – paxdiablo

+2

L'utente molto probabilmente è in contraddizione con se stesso: pylint non è lo strumento più esplicito in tal senso, ma gli avvertimenti dati di solito hanno una portata molto più profonda di quello che sembra dare il messaggio. Quindi l'utente potrebbe * pensare * a sapere quali conseguenze sono accettate, ma (s) non ne apprezza pienamente le implicazioni. –

14

È possibile modificare facilmente il numero massimo consentito di argomenti in pylint. Basta aprire il file pylintrc (generarlo se non ne hai già uno) e il cambiamento:

max-args = 5

a:

max-args = 6 # o qualsiasi valore che si adatta si

Da pylint di manual

Specifica tutte le opzioni adatte per la configurazione e standard di codifica può essere tedi ous, quindi è possibile utilizzare un file rc per specificare i valori di default . Pylint cerca/etc/pylintrc e ~/.pylintrc. L'opzione --generate-rcfile genererà un file di configurazione commentato in base alla configurazione corrente dello sullo standard output e exit. È possibile aggiungere altre opzioni prima di utilizzarle nella configurazione o iniziare con i valori predefiniti e regolare manualmente la configurazione .

3

Commento su risposta di paxdiablo - come io non ho abbastanza fama di commentare lì direttamente: -/

non mi piace riferimento al numero, il nome sybolic è molto più espressiva e evitare di dover aggiungere un commento che potrebbe diventare obsoleto nel tempo.

Quindi io preferirei fare:

#pylint: disable-msg=too-many-arguments 

e vorrei anche consigliare di non lasciarlo lì penzoloni: resterà attiva fino a quando il file termina o si è disattivato, si verifica per primo.

Quindi meglio fare:

#pylint: disable-msg=too-many-arguments 
code_which_would_trigger_the_msg 
#pylint: enable-msg=too-many-arguments  

Auspico inoltre abilitare/disabilitare un singolo avviso/errore per riga.

Problemi correlati