web-dev-qa-db-fra.com

Créer des propriétés d'instance de classe à partir d'un dictionnaire?

J'importe d'un fichier CSV et je reçois des données à peu près au format

{ 'Field1' : 3000, 'Field2' : 6000, 'RandomField' : 5000 }

Les noms des champs sont dynamiques. (Eh bien, ils sont dynamiques dans la mesure où il pourrait y avoir plus que Field1 et Field2, mais je sais que Field1 et Field2 seront toujours présents.

J'aimerais pouvoir transmettre ce dictionnaire à ma classe allMyFields afin de pouvoir accéder aux données ci-dessus en tant que propriétés.

class allMyFields:
    # I think I need to include these to allow hinting in Komodo. I think.
    self.Field1 = None
    self.Field2 = None

    def __init__(self,dictionary):
        for k,v in dictionary.items():
            self.k = v
            #of course, this doesn't work. I've ended up doing this instead
            #self.data[k] = v
            #but it's not the way I want to access the data.

q = { 'Field1' : 3000, 'Field2' : 6000, 'RandomField' : 5000 }
instance = allMyFields(q)
# Ideally I could do this.
print q.Field1

Aucune suggestion? En ce qui concerne la raison, j'aimerais pouvoir tirer parti des conseils de code, et importer les données dans un dictionnaire appelé data, comme je l'ai déjà fait, ne me le permet pas.

(Comme les noms de variables ne sont pas résolus avant l'exécution, je vais toujours devoir lancer un os à Komodo - je pense que le self.Field1 = None devrait suffire.)

Alors, comment puis-je faire ce que je veux? Ou suis-je en train d'aboyer un arbre mal conçu, non-python?

46
Rizwan Kassim

Vous pouvez utiliser setattr (attention cependant: chaque chaîne n'est pas un nom d'attribut valide!):

>>> class AllMyFields:
...     def __init__(self, dictionary):
...         for k, v in dictionary.items():
...             setattr(self, k, v)
... 
>>> o = AllMyFields({'a': 1, 'b': 2})
>>> o.a
1

Edit: laissez-moi vous expliquer la différence entre le code ci-dessus et la réponse de SilentGhost . L'extrait de code ci-dessus crée une classe dont attributs d'instance est basé sur un dictionnaire. Le code de SilentGhost crée une classe dont les attributs de classe sont basés sur un dictionnaire donné.

Selon votre situation spécifique, l’une ou l’autre de ces solutions peut être plus appropriée. Êtes-vous en train de créer une ou plusieurs instances de classe? Si la réponse est un, vous pouvez également ignorer la création d'objet et ne construire que le type (et aller ainsi avec la réponse de SilentGhost).

81
Stephan202
>>> q = { 'Field1' : 3000, 'Field2' : 6000, 'RandomField' : 5000 }
>>> q = type('allMyFields', (object,), q)
>>> q.Field1
3000

docs for type explique bien ce qui se passe ici (voir utilisation en tant que constructeur).

edit: si vous avez besoin de variables d'instance, ceci fonctionne aussi:

>>> a = q()             # first instance
>>> a.Field1
3000
>>> a.Field1 = 1
>>> a.Field1
1
>>> q().Field1           # second instance
3000
28
SilentGhost

Vous pouvez également utiliser dict.update au lieu de boucler manuellement sur items (et si vous faites une boucle, iteritems est préférable).

class allMyFields(object):
    # note: you cannot (and don't have to) use self here
    Field1 = None
    Field2 = None

    def __init__(self, dictionary):
        self.__dict__.update(dictionary)

q = { 'Field1' : 3000, 'Field2' : 6000, 'RandomField' : 5000 }
instance = allMyFields(q)

print instance.Field1      # => 3000
print instance.Field2      # => 6000
print instance.RandomField # => 5000
8
Cat Plus Plus

Utilisation de tuples nommés (Python 2.6):

>>> from collections import namedtuple

>>> the_dict = {'Field1': 3, 'Field2': 'b', 'foo': 4.9}
>>> fields = ' '.join(the_dict.keys())
>>> AllMyFields = namedtuple('AllMyFields', fields)
>>> instance = AllMyFields(**the_dict)

>>> print instance.Field1, instance.Field2, instance.foo
3 b 4.9
4

Vous pouvez créer une sous-classe de dict qui permet la recherche d'attributs pour les clés:

class AttributeDict(dict):
    def __getattr__(self, name):
        return self[name]

q = AttributeDict({ 'Field1' : 3000, 'Field2' : 6000, 'RandomField' : 5000 })
print q.Field1              
print q.Field2              
print q.RandomField

Si vous essayez de rechercher un attribut que dict a déjà (disons keys ou get), vous aurez cet attribut de classe dict (une méthode). Si la clé demandée n'existe pas dans la classe dict, la méthode __getattr__ sera appelée et effectuera votre recherche de clé. 

3
Matt Anderson

Utilisez setattr pour la belle façon. Le moyen le plus rapide est de mettre à jour le dictionnaire interne de l'instance:

>>> class A(object):
...    pass
...
>>> a = A()
>>> a.__dict__.update({"foo": 1, "bar": 2})
>>> a.foo
1
>>> a.bar
2
>>>
2
truppo
class SomeClass:
    def __init__(self,
                 property1,
                 property2):
       self.property1 = property1
       self.property2 = property2


property_dict = {'property1': 'value1',
                 'property2': 'value2'}
sc = SomeClass(**property_dict)
print(sc.__dict__)
0
perevertysh