Question

Savez-vous s’il existe une fonction intégrée pour créer un dictionnaire à partir d’un objet quelconque? J'aimerais faire quelque chose comme ça:

>>> class Foo:
...     bar = 'hello'
...     baz = 'world'
...
>>> f = Foo()
>>> props(f)
{ 'bar' : 'hello', 'baz' : 'world' }

REMARQUE: les méthodes ne doivent pas être incluses. Seuls les champs.

Était-ce utile?

La solution

Notez que la meilleure pratique dans Python 2.7 consiste à utiliser new-style classes (non nécessaire avec Python 3), c'est-à-dire

class Foo(object):
   ...

De plus, il existe une différence entre un "objet" et une "classe". Pour créer un dictionnaire à partir d'un objet arbitraire, il suffit d'utiliser __ dict __ . En général, vous déclarez vos méthodes au niveau classe et vos attributs au niveau instance, donc __ dict __ devrait convenir. Par exemple:

>>> class A(object):
...   def __init__(self):
...     self.b = 1
...     self.c = 2
...   def do_nothing(self):
...     pass
...
>>> a = A()
>>> a.__dict__
{'c': 2, 'b': 1}

Une meilleure approche (suggérée par robert dans les commentaires) est l'intégration vars fonction:

>>> vars(a)
{'c': 2, 'b': 1}

Sinon, selon ce que vous souhaitez faire, il peut être intéressant de hériter de dict . Ensuite, votre classe est déjà un dictionnaire et si vous le souhaitez, vous pouvez remplacer getattr et / ou setattr pour appeler et définir le dict. Par exemple:

class Foo(dict):
    def __init__(self):
        pass
    def __getattr__(self, attr):
        return self[attr]

    # etc...

Autres conseils

Au lieu de x .__ dict __ , il est en fait plus pythonique d'utiliser vars (x) .

Le dir intégré vous donnera tous les attributs de l'objet, y compris des méthodes spéciales telles que __ str __ , __ dict __ et toute une série d'autres probablement pas envie. Mais vous pouvez faire quelque chose comme:

>>> class Foo(object):
...     bar = 'hello'
...     baz = 'world'
...
>>> f = Foo()
>>> [name for name in dir(f) if not name.startswith('__')]
[ 'bar', 'baz' ]
>>> dict((name, getattr(f, name)) for name in dir(f) if not name.startswith('__')) 
{ 'bar': 'hello', 'baz': 'world' }

Donc, cela peut être étendu pour ne renvoyer que des attributs de données et non des méthodes, en définissant votre fonction props comme ceci:

import inspect

def props(obj):
    pr = {}
    for name in dir(obj):
        value = getattr(obj, name)
        if not name.startswith('__') and not inspect.ismethod(value):
            pr[name] = value
    return pr

Je me suis arrangé avec une combinaison des deux réponses:

dict((key, value) for key, value in f.__dict__.iteritems() 
    if not callable(value) and not key.startswith('__'))
  

Pour créer un dictionnaire à partir d'un objet arbitraire, il suffit d'utiliser __ dict __ .

Il manque les attributs que l'objet hérite de sa classe. Par exemple,

class c(object):
    x = 3
a = c()

hasattr (a, 'x') est vrai, mais 'x' n'apparaît pas dans un .__ dict __

Je pensais que je prendrais un peu de temps pour vous montrer comment traduire un objet en dict via dict (obj) .

class A(object):
    d = '4'
    e = '5'
    f = '6'

    def __init__(self):
        self.a = '1'
        self.b = '2'
        self.c = '3'

    def __iter__(self):
        # first start by grabbing the Class items
        iters = dict((x,y) for x,y in A.__dict__.items() if x[:2] != '__')

        # then update the class items with the instance items
        iters.update(self.__dict__)

        # now 'yield' through the items
        for x,y in iters.items():
            yield x,y

a = A()
print(dict(a)) 
# prints "{'a': '1', 'c': '3', 'b': '2', 'e': '5', 'd': '4', 'f': '6'}"

La section clé de ce code est la fonction __ iter __ .

Comme l'expliquent les commentaires, la première chose à faire est de récupérer les éléments de la classe et d'empêcher tout ce qui commence par '__'.

Une fois que vous avez créé ce dict , vous pouvez utiliser la fonction update dict et transmettre l'instance __ dict __ .

Ceci vous donnera un dictionnaire complet de membres classe + instance. Il ne reste plus maintenant qu’à les parcourir et à les rapporter.

De plus, si vous prévoyez d’utiliser beaucoup cela, vous pouvez créer un décorateur de classe @iterable .

def iterable(cls):
    def iterfn(self):
        iters = dict((x,y) for x,y in cls.__dict__.items() if x[:2] != '__')
        iters.update(self.__dict__)

        for x,y in iters.items():
            yield x,y

    cls.__iter__ = iterfn
    return cls

@iterable
class B(object):
    d = 'd'
    e = 'e'
    f = 'f'

    def __init__(self):
        self.a = 'a'
        self.b = 'b'
        self.c = 'c'

b = B()
print(dict(b))

Réponse tardive, mais à des fins d'exhaustivité et d'avantages pour les googleurs:

def props(x):
    return dict((key, getattr(x, key)) for key in dir(x) if key not in dir(x.__class__))

Cela n’affichera pas les méthodes définies dans la classe, mais les champs, y compris ceux affectés à lambdas ou ceux commençant par un double soulignement, seront toujours affichés.

Je pense que le moyen le plus simple est de créer un attribut getitem pour la classe. Si vous devez écrire sur l'objet, vous pouvez créer un setattr personnalisé. Voici un exemple pour getitem :

class A(object):
    def __init__(self):
        self.b = 1
        self.c = 2
    def __getitem__(self, item):
        return self.__dict__[item]

# Usage: 
a = A()
a.__getitem__('b')  # Outputs 1
a.__dict__  # Outputs {'c': 2, 'b': 1}
vars(a)  # Outputs {'c': 2, 'b': 1}

dict génère les attributs de l'objet dans un dictionnaire, qui peut être utilisé pour obtenir l'élément dont vous avez besoin.

Si vous souhaitez répertorier une partie de vos attributs, remplacez __ dict __ :

def __dict__(self):
    d = {
    'attr_1' : self.attr_1,
    ...
    }
    return d

# Call __dict__
d = instance.__dict__()

Cela aide beaucoup si votre instance récupère des données de bloc volumineuses et que vous souhaitez transmettre d à Redis comme une file d'attente de messages.

Un inconvénient de l’utilisation de __ dict __ est qu’il est superficiel; il ne convertira pas les sous-classes en dictionnaires.

Si vous utilisez Python 3.5 ou une version ultérieure, vous pouvez utiliser jsons :

>>> import jsons
>>> jsons.dump(f)
{'bar': 'hello', 'baz': 'world'}

PYTHON 3:

class DateTimeDecoder(json.JSONDecoder):

   def __init__(self, *args, **kargs):
        JSONDecoder.__init__(self, object_hook=self.dict_to_object,
                         *args, **kargs)

   def dict_to_object(self, d):
       if '__type__' not in d:
          return d

       type = d.pop('__type__')
       try:
          dateobj = datetime(**d)
          return dateobj
       except:
          d['__type__'] = type
          return d

def json_default_format(value):
    try:
        if isinstance(value, datetime):
            return {
                '__type__': 'datetime',
                'year': value.year,
                'month': value.month,
                'day': value.day,
                'hour': value.hour,
                'minute': value.minute,
                'second': value.second,
                'microsecond': value.microsecond,
            }
        if isinstance(value, decimal.Decimal):
            return float(value)
        if isinstance(value, Enum):
            return value.name
        else:
            return vars(value)
    except Exception as e:
        raise ValueError

Vous pouvez maintenant utiliser le code ci-dessus dans votre propre classe:

class Foo():
  def toJSON(self):
        return json.loads(
            json.dumps(self, sort_keys=True, indent=4, separators=(',', ': '), default=json_default_format), cls=DateTimeDecoder)


Foo().toJSON() 
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top