2012-09-20 19 views
12

Sé lo que significa subrayar doble para los atributos/métodos de la clase Python, pero ¿significa algo para el argumento de método?Doble guión bajo para el método Python * argumento *

Parece que no se puede pasar el argumento comenzando con doble guion bajo a los métodos. Es confuso porque puede hacer eso para las funciones normales.

consideran este 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) 

Al ejecutar este script de rendimientos:

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' 

he comprobado esto con Python 2.7.2.


Algunos otros ejemplos

funciona esto:

def egg(self, __a): 
    return __a 


class Spam(object): 

    egg = egg 

Spam().egg(__a=1) 

Esto no significa:

class Spam(object): 

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

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

Spam().egg(1) 

Respuesta

12

Nombre mangling se aplica a todos los identificadores con los principales subrayados dobles, regardless of where they occur (segundo a última oración en esa sección):

Esta transformación es independiente del contexto sintáctico en el que se utiliza el identificador.

Esto es más simple de implementar y definir, y más consistente. Puede parecer estúpido, pero todo el asunto de cambiar de nombre es un feo y pequeño truco en mi humilde opinión. y no se espera que use nombres así para nada, excepto atributos/métodos de todos modos.

Spam().egg(_Spam__a=1), así como Spam().egg(1), funciona. Pero a pesar de que puede hacer que funcione, los guiones bajos (cualquiera de ellos) no tienen cabida en los nombres de los parámetros. O en cualquier variable local (excepción: _) para el caso.

Editar: Parece que ha encontrado un caso de esquina que nadie haya considerado nunca. La documentación es imprecisa aquí, o la implementación es defectuosa. Parece que los nombres de los argumentos clave no están destrozados. Mire el código de bytes (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 

Esto puede tener sus raíces en el hecho de que los argumentos de palabras clave son equivalente a pasar un diccionario (en este caso {'__a': 1}) cuyas claves no serían destrozados tampoco. Pero, sinceramente, simplemente lo llamaría un caso de esquina feo en un caso especial ya feo y seguir adelante. No es importante porque de todos modos no deberías usar identificadores como ese.

+0

Si sucede "independientemente del lugar donde se producen", espero que el último ejemplo (la que he añadido) funciona. Supongo que sé por qué no lo hace; debería estar en "espacio de nombres de clase" o algo así (no sé cuál es la palabra correcta para eso), ¿verdad? – tkf

+0

También lo esperaría, y estoy bastante sorprendido. Supongo que es un defecto en la documentación o la implementación. Estoy editando ahora mismo para agregar mis hallazgos. – delnan

+0

Estoy de acuerdo en que no es un parámetro elegante, pero considere cuando tiene algo como 'self .__ dict __. Update (kwds)' en la función, pero quiere controlar el comportamiento de la función. El único nombre de argumento válido que puedo pensar para controlar el comportamiento es el que comienza con doble guion bajo. – tkf

3

que se convierte a _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

subrayado doble o Name Mangling en un contexto de clase es un identificador privado. En su ejemplo, pruebe dir (Spam.egg) y verá que el parámetro __a ahora es _Spam__egg.

Ahora puede utilizar:

Spam().egg(_Spam__a=1) 
Cuestiones relacionadas