2010-10-28 14 views
27

Me gustaría utilizar un atributo de clase como valor predeterminado para uno de los argumentos del método __init__ de mi clase. Esta construcción plantea una excepción NameError, sin embargo, y no entiendo por qué:¿Puedo usar un atributo de clase como valor predeterminado para un método de instancia?

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

¿Por qué esto falla, y hay una manera de hacer esto que funciona?

+0

Asegúrese para leer más allá de la respuesta aceptada menos útil a [la respuesta de Ethan] (http://stackoverflow.com/a/7697664/1709587), que proporciona una sintaxis de trabajo que le permite hacer esto. –

Respuesta

22

Eso es debido a que, de acuerdo con el documentation: valores de los parámetros

predeterminados se evalúa cuando se ejecuta la definición de función . Esto significa que la expresión se evalúa una vez, cuando la función se define

Cuando se define __init__(), la definición de MyClass es incompleta, ya que todavía está siendo analizada, por lo que no puede hacer referencia a MyClass.__DefaultName todavía . Una forma de evitar esto es para pasar un valor único especial para __init__(), como None:

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

Preferiría no mencionar la clase explícitamente por su nombre. ¿Cuál sería una forma recomendada de acceder a la clase y los atributos de clase de un método de instancia? Es 'tipo (self)' ok? – Alexey

20

Una cosa importante a tener en cuenta con Python es cuando se ejecutan trozos diferentes de código, junto con el hecho de que las instrucciones class y def se ejecutan cuando se ve, no solo se almacena para más adelante. Con un def que es un poco más fácil de entender, porque lo único que se está ejecutando es lo que está entre los () s - por lo que en el código anterior

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

cuando Python ve MyClass.__DefaultName se trata de encontrar por primera vez en la local espacio de nombres , luego el espacio de nombres del módulo (también conocido como global) y finalmente en builtins.

¿Qué es el espacio de nombre local al ejecutar una instrucción class? Esa es la parte divertida: es lo que se convertirá en el espacio de nombre class, pero en este momento es anónimo, por lo que no puede hacer referencia por su nombre (MyClass en su código) pero puede referenciar directamente cualquier cosa que tenga ya se ha definido ... y qué se ha definido? En su clase, solo hay una cosa: __DefaultName. Por lo que su __init__ debería tener este aspecto:

def __init__(SELF, name=__DefaultName): 

Tenga en cuenta que no se puede cambiar MyClass._MyClass__DefaultName más tarde y tienen esos cambios se muestran en nuevas instancias. ¿Por qué? Debido a que la definición __init__ se ejecuta sólo una vez, y cualquiera que sea el valor __DefaultName tenían en ese momento se ha guardado y se utilizará siempre - a menos que se especifique directamente un nuevo valor cuando se crea una nueva instancia:

my_instance = MyClass(name='new name') 
Cuestiones relacionadas