2010-04-06 9 views
10

Je dois créer dynamiquement des attributs de classe à partir d'un dictionnaire DEFAULTS.Création dynamique d'attributs de 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], ...) 

Je pourrais aussi obtenir cela en ayant sth. comme __init__ pour la création de classe, afin de créer dynamiquement ces attributs à partir du dictionnaire et d'économiser beaucoup de code et de travail stupide.

Comment voulez-vous faire cela?

Merci beaucoup d'avance!

Répondre

3

Je pense que ce cas pour métaclasse:

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

comment pouvons-nous passer par défaut, ou comment peut-on initialiser un objet de cette classe Paramètres –

+1

même question avec @vijayshanker – TomSawyer

+0

Le code dépend du dictionnaire 'defaults' étant en portée lors de la définition de la classe 'Settings'. –

19

Vous pouvez le faire sans métaclasses à l'aide de décorateurs. De cette façon est un peu plus clair 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 

Avant Python 2.6 décorateurs de classe n'étaient pas disponibles. Ainsi vous pouvez écrire:

dans les anciennes versions de python.

Dans l'exemple fourni apply_defaults est réutilisable ... Eh bien, sauf que les valeurs par défaut sont codés en dur dans le corps du décorateur :) Si vous avez un seul cas, vous pouvez même simplifier votre code à ceci:

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

Ceci est possible car les classes (au sens des types) sont des objets eux-mêmes en Python.

+1

Vous devez également retourner la classe "décorée" ('cls' dans le premier exemple) à la fin de la fonction de décorateur, n'est-ce pas? Cela m'a pris un moment pour comprendre, mais à moins que je ne le fasse, la classe sera égale à "Aucun" après la définition. Ai-je manqué quelque chose, comme par exemple un moyen de fournir la classe par référence? – Simon

+0

Une manière élégante. – zoujyjs

+0

Comment puis-je transmettre les valeurs par défaut au fichier comme ceci 'a = Paramètres (par défaut)' 'settings.py' est un fichier particulier – TomSawyer

0

Lors de la définition d'une classe, l'espace de noms local sera converti dans l'espace de nom de classe à la fin du corps de classe. En tant que tel, vous pouvez accomplir ceci avec:

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

-1 Le [documentation] (http://docs.python.org/library/functions. html? highlight = locals # locals) pour 'locals()' dit que le contenu du dictionnaire renvoyé ne doit pas être modifié. – martineau

+0

C'est intelligent. Merci. –