2010-04-06 27 views
10

Necesito crear dinámicamente atributos de clase a partir de un diccionario DEFAULTS.Crear dinámicamente atributos de clase

defaults = { 
    'default_value1':True, 
    'default_value2':True, 
    'default_value3':True, 
} 

class Settings(object): 
    default_value1 = some_complex_init_function(defaults[default_value1], ...) 
    default_value2 = some_complex_init_function(defaults[default_value2], ...) 
    default_value3 = some_complex_init_function(defaults[default_value3], ...) 

También podría lograr esto teniendo sth. como __init__ para la creación de clases, con el fin de crear dinámicamente estos atributos del diccionario y guardar un montón de código y trabajo estúpido.

¿Cómo harías esto?

¡Muchas gracias de antemano!

Respuesta

3

Creo que es el caso para la metaclase:

class SettingsMeta(type): 
    def __new__(cls, name, bases, dct): 
     for name, value in defaults.items(): 
      dct[name] = some_complex_init_function(value, ...) 
     return type.__new__(cls, name, bases, dct) 

class Settings(object): 
    __metaclass__ = SettingsMeta 
+2

¿cómo podemos pasar por defecto, o cómo podemos inicializar un objeto de esta clase Ajustes –

+1

misma pregunta con @vijayshanker – TomSawyer

+0

El código depende del 'diccionario defaults' estar en alcance al definir la clase 'Configuración'. –

19

que podría hacerlo sin metaclases utilizando decoradores. De esta manera es un poco más clara de la OMI:

def apply_defaults(cls): 
    defaults = { 
     'default_value1':True, 
     'default_value2':True, 
     'default_value3':True, 
    } 
    for name, value in defaults.items(): 
     setattr(cls, name, some_complex_init_function(value, ...)) 
    return cls 

@apply_defaults 
class Settings(object): 
    pass 

Antes de Python 2.6 decoradores de clase no estaban disponibles. Para que pueda escribir:

class Settings(object): 
    pass 
Settings = apply_defaults(Settings) 

en versiones anteriores de python.

En el ejemplo proporcionado apply_defaults es reutilizable ... Bueno, excepto que los valores por defecto están codificadas en el cuerpo del decorador :) Si sólo tiene un solo caso incluso se puede simplificar el código a esto:

defaults = { 
    'default_value1':True, 
    'default_value2':True, 
    'default_value3':True, 
} 

class Settings(object): 
    """Your implementation goes here as usual""" 

for name, value in defaults.items(): 
    setattr(Settings, name, some_complex_init_function(value, ...)) 

Esto es posible ya que las clases (en el sentido de tipos) son objetos en Python.

+1

También debe devolver la clase "decorada" ('cls' en el primer ejemplo) al final de la función de decorador, ¿no es así? Me tomó un tiempo darme cuenta, pero a menos que haga esto, la clase será igual a 'Ninguno' después de la definición. ¿Me estoy perdiendo algo, como por ejemplo alguna forma de suministrar la clase por referencia? – Simon

+0

Una manera elegante. – zoujyjs

+0

¿Cómo paso los valores predeterminados al archivo como este 'a = Configuraciones (predeterminadas)' 'settings.py' es un archivo particular – TomSawyer

0

Al definir una clase, el espacio de nombres local se convertirá en el espacio de nombres de la clase al final del cuerpo de la clase. Como tal, se puede lograr esto con:

class Settings(object): 
    for key, val in defaults.iteritems(): 
     locals()[key] = some_complex_init_function(val, ...) 
+1

-1 La [documentación] (http://docs.python.org/library/functions. html? highlight = locals # locals) para 'locals()' dice que el contenido del diccionario devuelto no debe modificarse. – martineau

+0

Esto es inteligente. Gracias. –

Cuestiones relacionadas