2010-04-06 12 views
10

Devo creare dinamicamente gli attributi di classe da un dizionario DEFAULTS.Creare dinamicamente gli attributi di classe

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], ...) 

Potrei anche farlo con sth. come __init__ per la creazione di classi, al fine di creare dinamicamente questi attributi dal dizionario e salvare un sacco di codice e lavoro stupido.

Come lo faresti?

Grazie mille in anticipo!

risposta

3

Penso che sia per caso metaclasse:

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

come facciamo a passare le impostazioni predefinite, o il modo in cui è possibile inizializzare un oggetto di questa classe Impostazioni –

+1

stessa domanda con @vijayshanker – TomSawyer

+0

Il codice dipende dal dizionario 'defaults' essere in ambito durante la definizione della classe 'Settings'. –

19

si potesse fare senza metaclassi utilizzando decoratori. In questo modo è un po 'più chiaro IMO:

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 

Prima di Python 2.6 decoratori di classe non erano disponibili. Quindi puoi scrivere:

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

nelle versioni precedenti di python.

Nell'esempio fornito apply_defaults è riutilizzabile ... Beh, tranne che i valori di default sono hard-coded nel corpo del decoratore :) Se si dispone di un solo caso si può anche semplificare il codice a questo:

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, ...)) 

Ciò è possibile poiché le classi (nel senso dei tipi) sono oggetti stessi in Python.

+1

Devi anche restituire la classe "decorata" ('cls' nel primo esempio) alla fine della funzione decoratore, non è vero? Mi ci è voluto un po 'per capire, ma a meno che non lo faccia la classe sarà uguale a "Nessuno" dopo la definizione. Mi manca qualcosa, come ad esempio un modo di fornire la classe di riferimento, invece? – Simon

+0

Un modo elegante. – zoujyjs

+0

Come faccio a passare i valori predefiniti al file come questo 'a = Impostazioni (default)' 'settings.py' è un particolare file – TomSawyer

0

Durante la definizione di una classe, lo spazio dei nomi locale verrà convertito nello spazio dei nomi della classe al termine del corpo della classe. Come tale, è possibile eseguire questa con:

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

-1 La [documentazione] (http://docs.python.org/library/functions. html? highlight = locals # locals) per 'locals()' dice che il contenuto del dizionario restituito non dovrebbe essere modificato. – martineau

+0

Questo è intelligente. Grazie. –

Problemi correlati