¿Cómo enumerar las propiedades de un objeto en Python?

133

IC # lo hacemos a través de la reflexión. En Javascript es simple como:

for(var propertyName in objectName)
    var currentPropertyValue = objectName[propertyName];

¿Cómo hacerlo en Python?

Jader Dias
fuente
3
Tenga en cuenta que esta pregunta es incorrecta. La mayoría de las respuestas son sobre enumerar miembros . Estaba buscando una forma de enumerar propiedades , es decir, miembros de una clase decorada con @property.
Tomasz Gandor

Respuestas:

153
for property, value in vars(theObject).iteritems():
    print property, ": ", value

Tenga en cuenta que en algunos casos raros hay una __slots__propiedad, tales clases a menudo no tienen __dict__.

Georg Schölly
fuente
1
ahora cómo cambiar el valor? en Javascript podría hacer: object [propiedad] = newValue. ¿Cómo hacerlo en Python?
Jader Dias el
39
use setattr () en su lugar.
Nelson
1
@ Nelson ¿Podría explicar por qué esa es una mejor opción? ¿Es más corto o hay consideraciones adicionales?
WhyNotHugo
8
@Hugo: Primero porque es "pitónico", en otras palabras, esa es la sintaxis que una gran mayoría de la comunidad espera ver. La otra sintaxis probablemente detendría innecesariamente a cualquiera que lea su código. Segundo, algunos tipos implementan un setter __setattr__(). Establecer valores directamente en el diccionario omite el definidor del objeto (y / o el de sus padres). Es bastante común en Python que sucedan más cosas de lo que parece a simple vista durante el establecimiento de atributos (por ejemplo, saneamiento), el uso setattr()asegura que no se lo pierda o se ve obligado a manejarlas explícitamente usted mismo.
Michael Ekoka
3
@ Hi-ángel que hace el trabajo. Sin embargo, lo que no funciona es la constelación de ideas preconcebidas y suposiciones que tiene el estado circundante frente a los miembros de objetos dinámicos en Python. vars()solo devuelve miembros estáticos (es decir, atributos de objeto y métodos registrados con ese objeto __dict__). No no regreso miembros dinámicos (es decir, atributos de los objetos y métodos dinámicamente definidos por de ese objeto __getattr__()método o magia similar). Con toda probabilidad, su file.ImplementationNamepropiedad deseada se define dinámicamente y, por lo tanto, no está disponible para vars()o dir().
Cecil Curry
69

Ver inspect.getmembers(object[, predicate]).

Devuelve todos los miembros de un objeto en una lista de pares (nombre, valor) ordenados por nombre. Si se proporciona el argumento de predicado opcional, solo se incluyen los miembros para los cuales el predicado devuelve un valor verdadero.

>>> [name for name,thing in inspect.getmembers([])]
['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', 
'__delslice__',    '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', 
'__getitem__', '__getslice__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__iter__', 
'__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__','__reduce_ex__', 
'__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__setslice__', 
'__sizeof__', '__str__', '__subclasshook__', 'append', 'count', 'extend', 'index', 
'insert', 'pop', 'remove', 'reverse', 'sort']
>>> 
gimel
fuente
Sí, esta respuesta es genial; Nunca he usado este módulo antes. getmembers () se implementa simplemente recorriendo los resultados de dir (objeto), por cierto.
Nelson
¿Puedes explicar por qué esto es mejor que acceder a dict ? La documentación de Python es menos que útil, especialmente porque normalmente usa el término en attributeslugar de members(¿hay alguna diferencia entre los dos?). Podrían haber arreglado el nombre en Python 3.0 para que sea coherente.
nikow
Vaya, quería decir __dict__, lo siento.
nikow
44
@nikow: inspect.getmembers () está garantizado para seguir trabajando incluso si cambian los detalles internos.
Georg Schölly
3
@NicholasKnight inspect.getmembers()termina dir()con los beneficios secundarios (en su mayoría insignificantes) de (A) que incluyen atributos de clase dinámica y atributos de metaclase y (B) excluye miembros que no coinciden con el predicado pasado. Bostezo, ¿verdad? inspect.getmembers()es apropiado para bibliotecas de terceros que admiten genéricamente todos los tipos de objetos posibles. Para casos de uso estándar, sin embargo, es dir()absolutamente suficiente.
Cecil Curry
66

dir()Es la manera simple. Mira aquí:

Guía para la introspección de Python

EBGreen
fuente
2
Algo a tener en cuenta en los documentos de Python, dado que dir () se proporciona principalmente como una conveniencia para su uso en una solicitud interactiva, trata de proporcionar un conjunto interesante de nombres más de lo que intenta proporcionar un conjunto de nombres definido de manera rigurosa o consistente, y su comportamiento detallado puede cambiar entre versiones. Por ejemplo, los atributos de metaclase no están en la lista de resultados cuando el argumento es una clase.
skyler
1
Esta respuesta es la mejor cuando se hace un trabajo de scratch en el CLI.
15 años de python (nunca trabajo a tiempo completo) y todavía me olvido dir()gracias.
Abhishek Dujari
14

La __dict__propiedad del objeto es un diccionario de todas sus otras propiedades definidas. Tenga en cuenta que las clases de Python pueden anular getattr y hacer cosas que parecen propiedades pero que no están en __dict__. También están las funciones integradas vars()y dir()que son diferentes en formas sutiles. Y __slots__puede reemplazar __dict__en algunas clases inusuales.

Los objetos son complicados en Python. __dict__es el lugar correcto para comenzar con la programación al estilo de reflexión. dir()es el lugar para comenzar si estás pirateando en un shell interactivo.

Nelson
fuente
print vars.__doc__indica que With an argument, equivalent to object.__dict__¿Cuáles serían las diferencias sutiles?
sancho.s ReinstateMonicaCellio
11

georg scholly versión más corta

print vars(theObject)
Nicolas Rojo
fuente
10

Si está buscando un reflejo de todas las propiedades, las respuestas anteriores son excelentes.

Si simplemente está buscando obtener las claves de un diccionario (que es diferente de un 'objeto' en Python), use

my_dict.keys()

my_dict = {'abc': {}, 'def': 12, 'ghi': 'string' }
my_dict.keys() 
> ['abc', 'def', 'ghi']
MrE
fuente
1
aunque es mi respuesta, no creo que deba ser la respuesta aceptada: las claves de un objeto son diferentes de la propiedad de una instancia de objeto de una clase. Se accede de manera diferente ( obj['key']vs. obj.property) y la pregunta era sobre las propiedades de los objetos. Puse mi respuesta aquí porque hay una fácil confusión entre los dos.
MrE
De hecho, sugeriría eliminar esta respuesta.
Ente
Como se indicó anteriormente, las personas que provienen de Javascript o C #, por ejemplo, se confunden fácilmente con la terminología, ya que no hay diferencia entre esos 2 conceptos. Es muy probable que las personas que aprenden python e intentan acceder a las claves busquen 'propiedades' y terminen aquí, de ahí por qué creo que pertenece.
MrE
y tiene razón, pero pierde el punto: en otros idiomas (tome JS) no hay distinción entre objeto y diccionario. El OP viene de C # haciendo la pregunta. Esta respuesta, aunque incorrecta, obtuvo 11 votos a favor, prueba de que las personas que aterrizan aquí lo encuentran útil, aunque técnicamente no es la respuesta correcta (como señalo) a la pregunta cuando se mira en estricta jerga de Python. Lo editaré para hacerlo aún más claro como el cristal.
MrE
5

Esto está totalmente cubierto por las otras respuestas, pero lo haré explícito. Un objeto puede tener atributos de clase y atributos de instancia estáticos y dinámicos.

class foo:
    classy = 1
    @property
    def dyno(self):
        return 1
    def __init__(self):
        self.stasis = 2

    def fx(self):
        return 3

stasises estático, dynoes dinámico (ver decorador de propiedades) y classyes un atributo de clase. Si simplemente lo hacemos __dict__o varssolo obtendremos el estático.

o = foo()
print(o.__dict__) #{'stasis': 2}
print(vars(o)) #{'stasis': 2}

Entonces, si queremos, los demás __dict__obtendrán todo (y más). Esto incluye métodos y atributos mágicos y métodos vinculados normales. Así que evitemos esos:

d = {k: getattr(o, k, '') for k in o.__dir__() if k[:2] != '__' and type(getattr(o, k, '')).__name__ != 'method'}
print(d) #{'stasis': 2, 'classy': 1, 'dyno': 1}

El typellamado con un método decorado de propiedad (un atributo dinámico) le dará el tipo del valor devuelto, no method. Para probar esto, json lo secuenciamos:

import json
print(json.dumps(d)) #{"stasis": 2, "classy": 1, "dyno": 1}

Si hubiera sido un método, se habría estrellado.

TL; DR. intenta llamar extravar = lambda o: {k: getattr(o, k, '') for k in o.__dir__() if k[:2] != '__' and type(getattr(o, k, '')).__name__ != 'method'}a los tres, pero no métodos ni magia.

Matteo Ferla
fuente