2012-09-20 16 views
12

So cosa significa doppio underscore per gli attributi/metodi della classe Python, ma significa qualcosa per l'argomento del metodo?Double underscore per il metodo Python * argomento *

Sembra che non sia possibile passare l'argomento iniziando con il doppio trattino basso sui metodi. È confuso perché puoi farlo per le normali funzioni.

considerare questo script:

def egg(__a=None): 
    return __a 

print "egg(1) =", 
print egg(1) 
print 


class Spam(object): 

    def egg(self, __a=None): 
     return __a 

print "Spam().egg(__a=1) =", 
print Spam().egg(__a=1) 

esecuzione di questo script rendimenti:

egg(1) = 1 

Spam().egg(__a=1) = 
Traceback (most recent call last): 
    File "/....py", line 15, in <module> 
    print Spam().egg(__a=1) 
TypeError: egg() got an unexpected keyword argument '__a' 

ho controllato questo con Python 2.7.2.


Alcuni altri esempi

funziona:

def egg(self, __a): 
    return __a 


class Spam(object): 

    egg = egg 

Spam().egg(__a=1) 

Questo non significa:

class Spam(object): 

    def _egg(self, __a=None): 
     return __a 

    def egg(self, a): 
     return self._egg(__a=a) 

Spam().egg(1) 

risposta

12

mutilazione dei nomi si applica a tutti gli identificatori con i principali doppia sottolineatura, regardless of where they occur (secondo a ultima frase in quella sezione):

Questa trasformazione è indipendente dal contesto sintattico in cui viene utilizzato l'identificatore.

Questo è più semplice da implementare e definire e più coerente. Può sembrare stupido, ma l'intero affare di mangling è un brutto scherzo IMHO; e non ci si aspetta che tu usi nomi del genere per qualsiasi cosa eccetto attributi/metodi comunque.

Spam().egg(_Spam__a=1), così come Spam().egg(1), funziona. Ma anche se puoi farlo funzionare, i trattini bassi (qualsiasi numero) non hanno posto nei nomi dei parametri. O in qualsiasi variabile locale (eccezione: _) per quella materia.

Modifica: Sembra che tu abbia trovato un caso d'angolo mai considerato. La documentazione è imprecisa qui, o l'implementazione è difettosa. Sembra che i nomi degli argomenti delle parole chiave non siano mutilati. Guardate il bytecode (Python 3.2):

>>> dis.dis(Spam.egg) 
    3   0 LOAD_FAST    0 (self) 
       3 LOAD_ATTR    0 (_egg) 
       6 LOAD_CONST    1 ('__a') # keyword argument not mangled 
       9 LOAD_FAST    1 (a) 
      12 CALL_FUNCTION   256 
      15 RETURN_VALUE 
>>> dis.dis(Spam._egg) 
    2   0 LOAD_FAST    1 (_Spam__a) # parameter mangled 
       3 RETURN_VALUE 

Questo può essere radicata nel fatto che gli argomenti chiave sono equivalenti a passare un dict (in questo caso {'__a': 1}) le cui chiavi non sarebbero alterati sia. Ma onestamente, lo definirei un brutto caso d'angolo in un caso speciale già brutto e andare avanti. Non è importante perché non dovresti usare identificatori del genere comunque.

+0

Se accade "indipendentemente da dove si verificano", mi aspetto l'ultimo esempio (quello ho aggiunto) funziona. Suppongo di sapere perché non lo fa; dovrebbe essere in "namespace di classe" o qualcosa del genere (non so qual è la parola giusta per questo), giusto? – tkf

+0

Anch'io me lo aspetto e sono abbastanza sorpreso. Immagino che sia un difetto nella documentazione o nell'implementazione. Sto modificando in questo momento per aggiungere le mie scoperte. – delnan

+0

Sono d'accordo sul fatto che non è un parametro elegante, ma considera quando hai qualcosa come 'self .__ dict __. Update (kwds)' nella funzione ma vuoi controllare il comportamento della funzione. L'unico nome argomento valido che posso pensare per controllare il comportamento è che inizia con il doppio trattino basso. – tkf

3

E viene convertito in _Spam__a:

In [20]: class Spam(object): 
    ....:  
    ....:   def egg(self, __a=None): 
    ....:    return __a 
    ....: 

In [21]: Spam.egg.__func__.__code__.co_varnames 
Out[21]: ('self', '_Spam__a') 
1

doppia sottolineatura o Name Mangling in un contesto classe è un identificatore privata. Nel tuo esempio prova dir (Spam.egg) e vedrai che il parametro __a è ora _Spam__egg.

È ora possibile utilizzare:

Spam().egg(_Spam__a=1) 
Problemi correlati