100 votes

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

Je suis en train d'importer à partir d'un fichier CSV et d'obtenir des données approximativement sous le format

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

Les noms des champs sont dynamiques. (Eh bien, ils sont dynamiques en ce sens qu'il pourrait y avoir plus que Field1 et Field2, mais je sais que Field1 et Field2 seront toujours là.

J'aimerais pouvoir passer ce dictionnaire dans ma classe allMyFields pour que je puisse accéder aux données ci-dessus en tant que propriétés.

classe allMyFields:
    # Je pense que j'ai besoin d'inclure cela pour permettre l'indication dans Komodo. Je pense.
    self.Field1 = None
    self.Field2 = None

    def __init__(self,dictionary):
        pour k,v in dictionary.items():
            self.k = v
            #bien sûr, cela ne fonctionne pas. J'ai fini par faire cela à la place
            #self.data[k] = v
            #mais ce n'est pas la façon dont je veux accéder aux données.

q = { 'Field1' : 3000, 'Field2' : 6000, 'RandomField' : 5000 }
instance = allMyFields(q)
# Idéalement je pourrais faire ceci.
print q.Field1

Des suggestions? En ce qui concerne pourquoi -- j'aimerais pouvoir profiter de l'indication de code, et l'importation des données dans un dictionnaire appelé data comme je l'ai fait jusqu'à présent ne me le permet pas.

(Puisque les noms de variables ne sont résolus qu'au moment de l'exécution, je vais quand même devoir filer un os à Komodo - je pense que le self.Field1 = None devrait suffire.)

Alors - comment puis-je faire ce que je veux? Ou est-ce que je pigeonne un arbre mal conçu, non-python?

5voto

En utilisant des 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

4voto

Colin Wang Points 161

Amélioré de sous-classe de dict

répétition dict fonctionne!

class AttributeDict(dict):
    """https://stackoverflow.com/a/1639632/6494418"""

    def __getattr__(self, name):
        return self[name] if not isinstance(self[name], dict) \
            else AttributeDict(self[name])

if __name__ == '__main__':
    d = {"hello": 1, "world": 2, "cat": {"dog": 5}}
    d = AttributeDict(d)
    print(d.cat)
    print(d.cat.dog)
    print(d.cat.items())

    """
    {'dog': 5}
    5
    dict_items([('dog', 5)])
    """

4voto

Ahmed Roshdy Points 156

Si vous êtes ouvert à l'ajout d'une nouvelle bibliothèque, pydantic est une solution très efficace. Il utilise l'annotation python pour construire l'objet et valider le type. Considérez le code suivant :

from pydantic import BaseModel

class Person(BaseModel):
    name: str
    age: str

data = {"name": "ahmed", "age": 36}

p = Person(**data)

pydantic: https://pydantic-docs.helpmanual.io/

3voto

perevertysh Points 31
classe SomeClass:
    def __init__(self,
                 propriété1,
                 propriété2):
       self.propriété1 = propriété1
       self.propriété2 = propriété2

dictionnaire_de_propriétés = {'propriété1': 'valeur1',
                 'propriété2': 'valeur2'}
sc = SomeClass(**dictionnaire_de_propriétés)
print(sc.__dict__)

2voto

Mitch Points 175

Ou vous pouvez essayer ceci

class AllMyFields:
    def __init__(self, field1, field2, random_field):
        self.field1 = field1
        self.field2 = field2
        self.random_field = random_field

    @classmethod
    def get_instance(cls, d: dict):
        return cls(**d)

a = AllMyFields.get_instance({'field1': 3000, 'field2': 6000, 'random_field': 5000})
print(a.field1)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X