recorrer - Diccionario de Python de los campos de un objeto
lista de diccionarios python (10)
¿Sabe si hay una función incorporada para construir un diccionario a partir de un objeto arbitrario? 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 métodos. Sólo campos.
Para construir un diccionario a partir de un objeto arbitrario, es suficiente usar
__dict__
.
Esto pierde los atributos que el objeto hereda de su clase. Por ejemplo,
class c(object):
x = 3
a = c()
hasattr (a, ''x'') es verdadero, pero ''x'' no aparece en un .__ dict__
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 puedes usar el código anterior dentro de tu 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()
Creo que la forma más fácil es crear un atributo getitem para la clase. Si necesita escribir en el objeto, puede crear un setattr personalizado. Aquí hay 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 los objetos en un diccionario y el objeto del diccionario se puede utilizar para obtener el elemento que necesita.
El dir
incorporado le proporcionará todos los atributos del objeto, incluidos métodos especiales como __str__
, __dict__
y __dict__
otros que probablemente no desee. 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í que puede extender esto para que solo devuelva atributos de datos y no métodos, definiendo su función de props
siguiente manera:
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
En lugar de x.__dict__
, en realidad es más pythónico usar vars(x)
.
Me he conformado 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(''__''))
Pensé que me tomaría un tiempo mostrarte cómo puedes traducir un objeto a dict a través de 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 sección clave de este código es la función __iter__
.
Como explican los comentarios, lo primero que hacemos es agarrar los elementos de la Clase y evitar todo lo que comience con ''__''.
Una vez que haya creado ese dict
, entonces puede usar la función de __dict__
update
y pasar la instancia __dict__
.
Estos te darán un completo diccionario de clase + instancia de miembros. Ahora todo lo que queda es iterar sobre ellos y producir los rendimientos.
Además, si planeas usar esto mucho, puedes crear un decorador de clase @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))
Respuesta tardía, pero siempre completa y en beneficio de los usuarios de Google:
def props(x):
return dict((key, getattr(x, key)) for key in dir(x) if key not in dir(x.__class__))
Esto no mostrará los métodos definidos en la clase, pero seguirá mostrando campos que incluyen aquellos asignados a las lambdas o aquellos que comienzan con un subrayado doble.
Si desea enumerar parte de sus atributos, __dict__
:
def __dict__(self):
d = {
''attr_1'' : self.attr_1,
...
}
return d
# Call __dict__
d = instance.__dict__()
Esto ayuda mucho si su instance
obtiene algunos datos de bloque grandes y desea empujar d
a Redis como la cola de mensajes.
Tenga en cuenta que la mejor práctica en Python 2.7 es usar clases de new-style (no necesarias con Python 3), es decir
class Foo(object):
...
Además, hay una diferencia entre un ''objeto'' y una ''clase''. Para construir un diccionario a partir de un objeto arbitrario, es suficiente usar __dict__
. Por lo general, declarará sus métodos a nivel de clase y sus atributos a nivel de instancia, por lo que __dict__
debería 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 la función vars
integrada:
>>> vars(a)
{''c'': 2, ''b'': 1}
Alternativamente, dependiendo de lo que quiera hacer, podría ser bueno heredar de dict
. Entonces su clase ya es un diccionario, y si lo desea, puede anular getattr
y / o setattr
para llamar y configurar el dict. Por ejemplo:
class Foo(dict):
def __init__(self):
pass
def __getattr__(self, attr):
return self[attr]
# etc...