2011-11-15 10 views
22

Voglio passare un argomento di default per un metodo di istanza utilizzando il valore di un attributo dell'istanza:Come passare un valore di argomento predefinito di un membro di istanza a un metodo?

class C: 
    def __init__(self, format): 
     self.format = format 

    def process(self, formatting=self.format): 
     print(formatting) 

Nel provare che, ottengo il seguente messaggio di errore:

NameError: name 'self' is not defined 

voglio il metodo per comportarsi in questo modo:

C("abc").process()  # prints "abc" 
C("abc").process("xyz") # prints "xyz" 

Qual è il problema qui, perché non funziona? E come potrei fare questo lavoro?

+0

non utilizzare il formato come nome della variabile, in quanto è funzione built-in in python. – Yajushi

+0

Modifica dell'errore di 'self' in' metodo di processo' –

risposta

31

Non è possibile definirlo come valore predefinito, poiché il valore predefinito viene valutato quando viene definito il metodo, ovvero prima che esistano istanze. Un facile work-around è quello di fare qualcosa di simile:

class C: 
    def __init__(self, format): 
     self.format = format 

    def process(self, formatting=None): 
     formatting = formatting if formatting is not None else self.format 
     print(formatting) 

self.format saranno utilizzati solo se formatting è None.


Per dimostrare il punto di come i valori di default di lavoro, vedere questo esempio:

def mk_default(): 
    print("mk_default has been called!") 

def myfun(foo=mk_default()): 
    print("myfun has been called.") 

print("about to test functions") 
myfun("testing") 
myfun("testing again") 

E l'uscita qui:

mk_default has been called! 
about to test functions 
myfun has been called. 
myfun has been called. 

Notate come mk_default è stato chiamato solo una volta, e che è successo prima che la funzione fosse mai chiamata!

+0

Credo che 'mk_default' è stato chiamato prima che le funzioni venissero chiamate poiché' foo = mk_default() 'lo chiamava, a causa della parentesi. Non dovrebbe essere 'pippo = mk_default'? Quindi il tuo esempio potrebbe cambiare in 'myfun (" testing ")' seguito da 'myfun()'. – gary

+0

Questa soluzione è ancora la soluzione consigliata? – confused00

+2

Si noti che 'formatting = formatting o self.format'sarà' formattazione' a 'self.format' se' formatting' è un valore falso, come 0. Questo mi morde. Un modo più sicuro è digitare 'formatting = formattazione se la formattazione non è None else self.format' o equivalente. – Godsmith

6

In Python, il nome self è non speciale. È solo una convenzione per il nome del parametro, motivo per cui esiste un parametro self in __init__. (In realtà, __init__ non è molto speciale sia, e in particolare lo fa non in realtà creare l'oggetto ... che è una storia più lunga)

C("abc").process() crea un'istanza C, guarda in alto il metodo process nella classe C, e chiama questo metodo con l'istanza C come primo parametro. Quindi finirà nel parametro self se lo hai fornito.

Anche se si dispone di tale parametro, tuttavia, non è possibile scrivere qualcosa come def process(self, formatting = self.formatting), perché self non è ancora in ambito nel punto in cui si imposta il valore predefinito. In Python, il valore predefinito per un parametro viene calcolato quando la funzione viene compilata e "bloccata" nella funzione. (Questo è lo stesso motivo per cui, se si utilizza un valore predefinito come [], tale elenco si ricorderà le modifiche tra le chiamate alla funzione.)

Come potrei fare questo lavoro?

Il modo tradizionale è quello di utilizzare None come impostazione predefinita e verificare tale valore e sostituirlo all'interno della funzione.Potresti scoprire che è un po 'più sicuro creare un valore speciale per lo scopo (è sufficiente un'istanza object, purché la nascondi in modo che il codice chiamante non utilizzi la stessa istanza) anziché None. In entrambi i casi, è necessario verificare questo valore con is, non ==.

+0

La soluzione alternativa non soddisfa l'output desiderato sull'utilizzo di Nessuno. –

+0

Se 'None' è un valore valido per' formatting', allora dovrai scegliere qualcos'altro, come ho spiegato. –

1

"self" deve essere passato come primo argomento a qualsiasi funzione di classe se si desidera che si comportino come metodi non statici.

si riferisce all'oggetto stesso. Non è possibile passare "self" come argomento predefinito in quanto la posizione è fissa come primo argomento.

Nel tuo caso invece di "formattazione = self.format" uso "formattazione = None" e quindi assegnare il valore dal codice, come di seguito:

[EDIT]

class c: 
     def __init__(self, cformat): 
      self.cformat = cformat 

     def process(self, formatting=None): 
      print "Formating---",formatting 
      if formatting == None: 
       formatting = self.cformat 
       print formatting 
       return formatting 
      else: 
       print formatting 
       return formatting 

c("abc").process()   # prints "abc" 
c("abc").process("xyz")  # prints "xyz" 

Nota: non utilizzare "format" come nome della variabile, perché è funzione built-in in python

+0

Bene, ho corretto il problema 'self'. Ma la tua risposta non soddisfa l'output desiderato. –

+0

controlla blocco modificato, sarebbe di aiuto. – Yajushi

Problemi correlati