Pregunta

¿Sabe usted si hay una función incorporada para construir un diccionario de un objeto cualquiera?Me gustaría hacer algo como esto:

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

NOTA: No debe incluir los métodos.Sólo los campos.

¿Fue útil?

Solución

Tenga en cuenta que la mejor práctica en Python 2.7 es nuevo estilo clases (no es necesario con Python 3), es decir,

class Foo(object):
   ...

También, hay una diferencia entre un 'objeto' y una 'clase'.Construir un diccionario de una arbitraria objeto, es suficiente para el uso __dict__.Por lo general, usted va a declarar sus métodos a nivel de clase y sus atributos en el nivel de instancia, por lo que __dict__ debe estar bien.Por ejemplo:

>>> 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}

Un mejor enfoque (sugerido por robert en los comentarios) es el grupo builtin vars función:

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

Alternativamente, dependiendo de lo que quieras hacer, también podría ser bueno para heredar de dict.La clase es ya un diccionario, y si lo desea, puede reemplazar getattr y/o setattr para llamar a través de y establecer el dict.Por ejemplo:

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

    # etc...

Otros consejos

En lugar de x.__dict__, es, en realidad, el uso de python vars(x).

El dir builtin le dará todos los atributos del objeto, incluyendo los métodos especiales como __str__, __dict__ y un montón de otros que probablemente no quieres.Pero puedes hacer algo como:

>>> 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' }

Así puede extender esto para devolver sólo los atributos de datos y no los métodos, mediante la definición de su props función como esta:

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

He resuelto con una combinación de ambas respuestas:

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

Construir un diccionario de una arbitraria objeto, es suficiente para el uso __dict__.

Este pierde los atributos que el objeto hereda de su clase.Por ejemplo,

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

hasattr(a, 'x') es cierto, pero " x " no aparece en una.__dict__

Pensé en tomar algún tiempo para mostrar cómo se puede traducir a un objeto a través de la dict 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 clave de la sección de este código es el __iter__ la función.

Como los comentarios de explicar, la primera cosa que hacer es tomar la Clase de elementos y evitar cualquier cosa que empieza con '__'.

Una vez que hayas creado que dict, usted puede utilizar el update dict función y pasar en la instancia __dict__.

Estos le darán una clase completa+instancia diccionario de los miembros.Ahora todo lo que queda es para iterar sobre ellos y el rendimiento de la devuelve.

También, si usted planea usar mucho esto, usted puede crear un @iterable la clase decorator.

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

Tardanza en responderte, pero siempre la integridad y el beneficio de los empleados:

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

Esto no va a mostrar los métodos definidos en la clase, pero aún así se muestran los campos incluidos los asignados a las lambdas o aquellos que comienzan con un carácter de subrayado doble.

Creo que la forma más fácil es crear un getitem atributo de la clase.Si usted necesita para escribir en el objeto, puede crear uno personalizado setattr .Aquí es un ejemplo para 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 genera los atributos de objetos en un diccionario y el diccionario objeto puede ser usado para obtener el artículo que usted necesita.

Si quieres ver parte de sus atributos, anular __dict__:

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

# Call __dict__
d = instance.__dict__()

Esto ayuda mucho, si su instance obtener algunos de los grandes bloques de datos, y usted quiere empujar d a Redis como la cola de mensajes.

Un inconveniente del uso de __dict__ es que es poco profunda;no convertir cualquier subclases de los diccionarios.

Si usted está usando Python3.5 o posterior, puede utilizar 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

Ahora usted puede utilizar el código anterior dentro de su propia clase :

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() 
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top