Cómo convertir una cadena en un subatributo de clase con Python

Sé que puedo obtener los atributos de una Clase con una cadena como esta:

object.attribute = 'foo'
x = 'attribute'
getattr(object, x)
>>> 'foo'

¿Hay alguna manera de "profundizar" en los atributos del objeto con una cadena? En otras palabras, si mi objeto contiene otro objeto, ¿cómo puedo obtener los atributos del subobjeto con una cadena? Por ejemplo:

object.object.attribute

preguntado el 04 de julio de 12 a las 04:07

3 Respuestas

El operator.attrgetter función hace esto:

class Foo: pass
f = Foo()
f.bar = Foo()
f.bar.baz = Foo()
f.bar.baz.quux = "Found me!"

import operator
print operator.attrgetter("bar.baz.quux")(f)     # prints "Found me!"

Respondido 04 Jul 12, 04:07

¡DECIR AH! olvidé el attrgetter sigue la notación de puntos - jdi

Aún mejor, pero gracias de todos modos @jdi... Aprendí más sobre lambdas de tu respuesta. - MFB

@MFB: No te preocupes. La respuesta de Ned es mejor ya que es una versión stdlib de lo mismo que también es más rápida. - jdi

Me encanta la receta dada en este aquí (aunque en realidad el comentario es aún mejor)

Ejemplo tomado de la respuesta de Claudiu (que también es genial):

class Foo: pass
f = Foo()
f.bar = Foo()
f.bar.baz = Foo()
f.bar.baz.quux = "Found me!"

Un getattr recursivo que sigue a los puntos:

>>> rgetattr = lambda o,a: reduce(getattr, a.split('.'), o)
>>> rgetattr(f, 'bar.baz.quux')
'Found me!'

La versión no lambda es:

def rgetattr(obj, attr):
    return reduce(getattr, attr.split('.'), obj)

Respondido 04 Jul 12, 04:07

Oh booyah. Gracias a @Claudiu también - MFB

ah, últimamente no he estado haciendo suficiente programación funcional. Totalmente no vi esto como un reduce, pero obviamente es - Claudiu

>>> class Foo: pass

>>> f = Foo()
>>> f.bar = Foo()
>>> f.bar.baz = Foo()
>>> f.bar.baz.quux = "Found me!"
>>> getattr(f, 'bar')
<__main__.Foo instance at 0x01EC5918>
>>> getattr(getattr(f, 'bar'), 'baz')
<__main__.Foo instance at 0x01EC5A30>
>>> getattr(getattr(getattr(f, 'bar'), 'baz'), 'quux')
'Found me!'

EDITAR: Hecho como un método simple:

>>> def dynamic_lookup(obj, dot_attrs):
    attr_list = dot_attrs.split(".")
    while attr_list:
        obj = getattr(obj, attr_list.pop(0))
    return obj

>>> f
<__main__.Foo instance at 0x01EC50A8>
>>> dynamic_lookup(f, 'bar.baz.quux')
'Found me!'

Fácilmente adaptable para tomar una lista de cadenas (tomar attr_list directamente en lugar de dot_attrs), pero pensé que el . la notación como una cadena se vería mejor...

Respondido 04 Jul 12, 04:07

Ah, sí, pero ¿qué pasa con object.object.object.attribute? j/k :-)- jdi

Eso es genial. ¿Cómo podría construir el método final a partir de una lista de cadenas? - MFB

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.