Python diccionario de un objeto de campos
-
09-06-2019 - |
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.
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()