2010-10-28 10 views
27

Vorrei utilizzare un attributo di classe come valore predefinito per uno degli argomenti del metodo __init__ della mia classe. Questo costrutto solleva un'eccezione NameError, però, e non capisco perché:Posso usare un attributo di classe come valore predefinito per un metodo di istanza?

class MyClass(): 
    __DefaultName = 'DefaultName' 
    def __init__(self, name = MyClass.__DefaultName): 
     self.name = name 

Perché questo falliscono, e c'è un modo per fare questo che funziona?

+0

Assicurarsi per leggere la risposta meno utile accettata a [risposta di Ethan] (http://stackoverflow.com/a/7697664/1709587), che fornisce la sintassi di lavoro che ti consente di farlo. –

risposta

22

Questo perché, secondo l'documentation: valori dei parametri

predefiniti vengono valutati quando viene eseguita la definizione della funzione . Ciò significa che l'espressione viene valutata una volta, quando la funzione è definita

Quando __init__() è definito, la definizione di MyClass è incompleta, come è ancora analizzato, quindi non è possibile fare riferimento a MyClass.__DefaultName ancora . Un modo per aggirare che deve passare un valore univoco speciale __init__(), come None:

def __init__(self, name=None): 
    if name is None: 
     name = MyClass.__DefaultName 
    # ... 
+0

Preferirei non menzionare la classe esplicitamente per nome. Quale sarebbe un modo consigliato per accedere alla classe e agli attributi della classe da un metodo di istanza? 'Type (self)' ok? – Alexey

20

Una cosa importante da tenere a mente con Python è quando vengono eseguiti diversi bit di codice, insieme con il In effetti, le istruzioni class e def vengono eseguite quando è visto, non solo archiviato per un secondo momento. Con un def è un po 'più facile da capire perché l'unica cosa che viene eseguito è tutto ciò che è tra le () s - così nel codice sopra

def __init__(SELF, name = MyClass.__DefaultName): 

quando Python vede MyClass.__DefaultName si cerca di trovare in primo luogo nella local namespace , quindi il modulo (aka global) spazio dei nomi e infine in builtins.

Che cos'è lo spazio dei nomiquando si esegue un'istruzione class? Questa è la parte divertente - è quello che diventerà lo spazio dei nomi class, ma al momento è anonimo - quindi non puoi fare riferimento per nome (ovvero MyClass nel tuo codice) ma tu puoi fare riferimento direttamente a qualsiasi cosa abbia già stato definito ... e cosa è stato definito? Nel tuo esempio di classe solo una cosa - __DefaultName. Così il vostro __init__ dovrebbe assomigliare a questo:

def __init__(SELF, name=__DefaultName): 

Tenete a mente che non si può cambiare MyClass._MyClass__DefaultName più tardi e avere quelle modifiche compaiano in nuove istanze. Perché? Poiché il __init__ def viene eseguito solo una volta, e qualsiasi valore __DefaultName aveva in quel momento è stato messo da parte e verranno sempre utilizzati - a meno che non si specifica direttamente un nuovo valore quando si crea una nuova istanza:

my_instance = MyClass(name='new name') 
Problemi correlati