Lista de atributos de un objeto

330

¿Hay alguna manera de obtener una lista de atributos que existen en las instancias de una clase?

class new_class():
    def __init__(self, number):
        self.multi = int(number) * 2
        self.str = str(number)

a = new_class(2)
print(', '.join(a.SOMETHING))

El resultado deseado es que se generará "multi, str". Quiero que esto vea los atributos actuales de varias partes de un script.

MadSc13ntist
fuente
75
Prácticamente todos en Python nombran sus clases como NewClass. Puede desafiar las expectativas de las personas si usa una convención de nomenclatura como new_class.
Mike Graham el
A pesar de que es interactivo con humanos y no se puede usar mediante programación, la help()función ayuda a obtener información sobre clases, funciones, módulos integrados y más
ytpillai
1
Relevante: stackoverflow.com/questions/1398022/…
sancho.s ReinstateMonicaCellio
¿Por qué ninguna de las respuestas está marcada como 'Aceptada'?
pfabri

Respuestas:

295
>>> class new_class():
...   def __init__(self, number):
...     self.multi = int(number) * 2
...     self.str = str(number)
... 
>>> a = new_class(2)
>>> a.__dict__
{'multi': 4, 'str': '2'}
>>> a.__dict__.keys()
dict_keys(['multi', 'str'])

También puede encontrar útil pprint .


fuente
29
El problema del uso de dict acaba de aparecer en r / python. alguien señaló que vars (a) es equivalente a un .__ dict__
David
55
En caso de que alguien se pregunte, esto también funciona en Python 2.7
Ben Mordecai
8
Para ser específicos, pprint.pprint(a.__dict__)hace una bonita impresión en los atributos.
smci
1
Definitivamente eso pprintNO funciona en Python 2.6.
John Greene
3
Tenga en cuenta que esto solo funciona para las clases definidas por el usuario, no para los tipos integrados o de extensión.
ivan_pozdeev
173
dir(instance)
# or (same value)
instance.__dir__()
# or
instance.__dict__

Luego puede probar qué tipo es con type()o si es un método con callable().

Htechno
fuente
dir funcionó mejor en clases con atributo sobrecargado get / set
ogurets
dir (instancia) enumera muchas cosas que probablemente no le interesen
jciloa
Esta fue la única función que me dio todos los atributos disponibles en el bostonconjunto de datos de sklearn: __dict__estaba vacía, cuando en realidad había 5 atributos disponibles
Coruscate5 el
72

vars(obj) devuelve los atributos de un objeto.

rohithpr
fuente
54

Todas las respuestas anteriores son correctas, tiene tres opciones para lo que está preguntando.

  1. dir()

  2. vars()

  3. __dict__

>>> dir(a)
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'multi', 'str']
>>> vars(a)
{'multi': 4, 'str': '2'}
>>> a.__dict__
{'multi': 4, 'str': '2'}
grepit
fuente
1
vars(foo)regresafoo.__dict__
Boris
32
>>> ', '.join(i for i in dir(a) if not i.startswith('__'))
'multi, str'

Esto, por supuesto, imprimirá cualquier método o atributo en la definición de clase. Puede excluir métodos "privados" cambiando i.startwith('__')ai.startwith('_')

SilentGhost
fuente
24

El módulo de inspección proporciona formas fáciles de inspeccionar un objeto:

El módulo de inspección proporciona varias funciones útiles para ayudar a obtener información sobre objetos vivos como módulos, clases, métodos, funciones, trazas, objetos de marco y objetos de código.


Utilizando getmembers()puedes ver todos los atributos de tu clase, junto con su valor. Para excluir el uso de atributos privados o protegidos .startswith('_'). Para excluir métodos o funciones, use inspect.ismethod()o inspect.isfunction().

import inspect


class NewClass(object):
    def __init__(self, number):
        self.multi = int(number) * 2
        self.str = str(number)

    def func_1(self):
        pass


a = NewClass(2)

for i in inspect.getmembers(a):
    # Ignores anything starting with underscore 
    # (that is, private and protected attributes)
    if not i[0].startswith('_'):
        # Ignores methods
        if not inspect.ismethod(i[1]):
            print(i)

Tenga en cuenta que ismethod()se utiliza en el segundo elemento de iya que el primero es simplemente una cadena (su nombre).

Offtopic: Use CamelCase para los nombres de clase.

Paradoja de Fermi
fuente
13

Puede usar dir(your_object)para obtener los atributos y getattr(your_object, your_object_attr)obtener los valores

uso:

for att in dir(your_object):
    print (att, getattr(your_object,att))

Esto es particularmente útil si su objeto no tiene __dict__. Si ese no es el caso, puede probar var (your_object) también

Jason Angel
fuente
11

A menudo se menciona que para enumerar una lista completa de atributos debe usar dir(). Sin embargo, tenga en cuenta que, contrariamente a la creencia popular dir(), no resalta todos los atributos. Por ejemplo, puede notar que __name__puede faltar en la dir()lista de una clase a pesar de que puede acceder desde la misma clase. Desde el documento en adelante dir()( Python 2 , Python 3 ):

Debido a que dir () se proporciona principalmente como una conveniencia para su uso en una solicitud interactiva, intenta 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 a través de las versiones. Por ejemplo, los atributos de metaclase no están en la lista de resultados cuando el argumento es una clase.

Una función como la siguiente tiende a ser más completa, aunque no hay garantía de integridad ya que la lista devuelta dir()puede verse afectada por muchos factores, incluida la implementación del __dir__()método, la personalización __getattr__()o __getattribute__()la clase o uno de sus padres. Vea los enlaces provistos para más detalles.

def dirmore(instance):
    visible = dir(instance)
    visible += [a for a in set(dir(type)).difference(visible)
                if hasattr(instance, a)]
    return sorted(visible)
Michael Ekoka
fuente
9

¿Para qué quieres esto? Puede ser difícil obtener la mejor respuesta sin conocer su intención exacta.

  • Casi siempre es mejor hacerlo manualmente si desea mostrar una instancia de su clase de una manera específica. Esto incluirá exactamente lo que desea y no incluirá lo que no desea, y el orden será predecible.

    Si está buscando una manera de mostrar el contenido de una clase, formatee manualmente los atributos que le interesan y proporcione esto como el método __str__o __repr__para su clase.

  • Si desea conocer qué métodos y tales existen para que un objeto entienda cómo funciona, utilícelo help. help(a)le mostrará una salida formateada sobre la clase del objeto en función de sus cadenas de documentos.

  • direxiste para obtener programáticamente todos los atributos de un objeto. (El acceso __dict__hace algo que yo agruparía igual pero que no usaría yo mismo). Sin embargo, esto puede no incluir las cosas que desea y puede incluir cosas que no desea. No es confiable y la gente piensa que lo quieren mucho más a menudo que ellos.

  • En una nota algo ortogonal, hay muy poco soporte para Python 3 en este momento. Si está interesado en escribir software real, querrá cosas de terceros como numpy, lxml, Twisted, PIL o cualquier cantidad de marcos web que aún no sean compatibles con Python 3 y que no tengan planes para hacerlo demasiado pronto. Las diferencias entre 2.6 y la rama 3.x son pequeñas, pero la diferencia en el soporte de la biblioteca es enorme.

Mike Graham
fuente
44
Solo debo señalar que cinco años después (ahora), creo que todos los módulos de terceros que mencionas son compatibles con python3. Fuente: python3wos.appspot.com
pzkpfw
8

Hay más de una forma de hacerlo:

#! /usr/bin/env python3
#
# This demonstrates how to pick the attiributes of an object

class C(object) :

  def __init__ (self, name="q" ):
    self.q = name
    self.m = "y?"

c = C()

print ( dir(c) )

Cuando se ejecuta, este código produce:

jeffs@jeff-desktop:~/skyset$ python3 attributes.py 
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__',      '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'm', 'q']

jeffs@jeff-desktop:~/skyset$
usuario1928764
fuente
2
¿Por qué esta respuesta ha sido rechazada? Para fines de depuración, dir funciona bastante bien.
Dunatotatos
Pretty funciona con Python 2.7.x. Exactamente lo que quería.
Davidson Lima
7

Consulte el script de shell de Python que se ha ejecutado en secuencia, aquí obtendrá los atributos de una clase en formato de cadena separados por comas.

>>> class new_class():
...     def __init__(self, number):
...         self.multi = int(number)*2
...         self.str = str(number)
... 
>>> a = new_class(4)
>>> ",".join(a.__dict__.keys())
'str,multi'<br/>

Estoy usando python 3.4

Lokesh kumar
fuente
Y si quieres solo la lista puede usar solo a.__dict__.keys(). Sin embargo, si desea saber si un objeto tiene un atributo específico, puede usarlo hasattr.
berna1111
4

Además de estas respuestas, incluiré una función (python 3) para escupir prácticamente toda la estructura de cualquier valor. Se usa dirpara establecer la lista completa de nombres de propiedades, luego se usa getattrcon cada nombre. Muestra el tipo de cada miembro del valor y, cuando es posible, también muestra el miembro completo:

import json

def get_info(obj):

  type_name = type(obj).__name__
  print('Value is of type {}!'.format(type_name))
  prop_names = dir(obj)

  for prop_name in prop_names:
    prop_val = getattr(obj, prop_name)
    prop_val_type_name = type(prop_val).__name__
    print('{} has property "{}" of type "{}"'.format(type_name, prop_name, prop_val_type_name))

    try:
      val_as_str = json.dumps([ prop_val ], indent=2)[1:-1]
      print('  Here\'s the {} value: {}'.format(prop_name, val_as_str))
    except:
      pass

Ahora, cualquiera de los siguientes debe dar una idea:

get_info(None)
get_info('hello')

import numpy
get_info(numpy)
# ... etc.
Gershom
fuente
Wow, eso es una joya!
pfabri
Sí, esto fue un salvavidas. no podía entender por qué esto no podía descomprimir fácilmente estas listas y, efectivamente, el tipo tiene propiedades " ranuras " de tipo "tupla" Aquí está el valor de las ranuras : ["nsname", "hostmaster", "serial", "actualizar", "retry", "caduca", "minttl", "ttl"]
Mik R
3

Obtener atributos de un objeto

class new_class():
    def __init__(self, number):
    self.multi = int(number) * 2
    self.str = str(number)

new_object = new_class(2)                
print(dir(new_object))                   #total list attributes of new_object
attr_value = new_object.__dict__         
print(attr_value)                        #Dictionary of attribute and value for new_class                   

for attr in attr_value:                  #attributes on  new_class
    print(attr)

Salida

['__class__', '__delattr__', '__dict__', '__dir__', '__doc__','__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'multi', 'str']

{'multi': 4, 'str': '2'}

multi
str
Bendito
fuente
1

Como se escribió antes de usar, obj.__dict__puede manejar casos comunes, pero algunas clases no tienen el __dict__atributo y usan__slots__ (principalmente para la eficiencia de la memoria).

ejemplo para una forma más resistente de hacer esto:

class A(object):
    __slots__ = ('x', 'y', )
    def __init__(self, x, y):
        self.x = x
        self.y = y


class B(object):
    def __init__(self, x, y):
        self.x = x
        self.y = y


def get_object_attrs(obj):
    try:
        return obj.__dict__
    except AttributeError:
        return {attr: getattr(obj, attr) for attr in obj.__slots__}


a = A(1,2)
b = B(1,2)
assert not hasattr(a, '__dict__')

print(get_object_attrs(a))
print(get_object_attrs(b))

salida de este código:

{'x': 1, 'y': 2}
{'x': 1, 'y': 2}

Nota 1:
Python es un lenguaje dinámico y siempre es mejor conocer las clases de las que intenta obtener los atributos, ya que incluso este código puede pasar por alto algunos casos.

Nota 2:
este código solo genera variables de instancia, lo que significa que no se proporcionan variables de clase. por ejemplo:

class A(object):
    url = 'http://stackoverflow.com'
    def __init__(self, path):
        self.path = path

print(A('/questions').__dict__)

salidas de código:

{'path': '/questions'}

Este código no imprime el urlatributo de clase y puede omitir los atributos de clase deseados.
A veces podríamos pensar que un atributo es un miembro de instancia, pero no lo es y no se mostrará con este ejemplo.

ShmulikA
fuente
2
Una clase puede tener __dict__ y __slots__ , por lo tanto, es probable que desee probar ambos en lugar de solo el dict.
cz
1
  • Usar __dict__o vars no funciona porque se pierde__slots__ .
  • Usando __dict__y __slots__ no funciona porque se pierde__slots__ de las clases base.
  • Usar dir no funciona porque incluye atributos de clase, como métodos o propiedades, así como los atributos del objeto.
  • Usar varses equivalente a usar __dict__.

Esto es lo mejor que tengo:

from typing import Dict

def get_attrs( x : object ) -> Dict[str, object]:
    mro      = type( x ).mro()
    attrs    = { }
    has_dict = False
    sentinel = object()

    for klass in mro:
        for slot in getattr( klass, "__slots__", () ):
            v = getattr( x, slot, sentinel )

            if v is sentinel:
                continue

            if slot == "__dict__":
                assert not has_dict, "Multiple __dicts__?"
                attrs.update( v )
                has_dict = True
            else:
                attrs[slot] = v

    if not has_dict:
        attrs.update( getattr( x, "__dict__", { } ) )

    return attrs
cz
fuente
Apliquemos esta función a la clase simple spome: clase C: def __init __ (self): print ("created") i = 42 ¿Por qué su código proporciona una lista vacía para dicha clase? (Quiero decir que si o = C (), entonces get_attrs (o) está vacío) También lo hizo para get_attrs ("mystr")
ged
0
attributes_list = [attribute for attribute in dir(obj) if attribute[0].islower()]
shammerw0w
fuente
No funciona con nombres de atributos de clase que comienzan con una letra mayúscula o un guión bajo.
fviktor
0

Consulte la siguiente ejecución de secuencia de comandos de shell Python en secuencia, dará la solución desde la creación de la clase hasta la extracción de los nombres de campo de las instancias.

>>> class Details:
...       def __init__(self,name,age):
...           self.name=name
...           self.age =age
...       def show_details(self):
...           if self.name:
...              print "Name : ",self.name
...           else:
...              print "Name : ","_"
...           if self.age:
...              if self.age>0:
...                 print "Age  : ",self.age
...              else:
...                 print "Age can't be -ve"
...           else:
...              print "Age  : ","_"
... 
>>> my_details = Details("Rishikesh",24)
>>> 
>>> print my_details
<__main__.Details instance at 0x10e2e77e8>
>>> 
>>> print my_details.name
Rishikesh
>>> print my_details.age
24
>>> 
>>> my_details.show_details()
Name :  Rishikesh
Age  :  24
>>> 
>>> person1 = Details("",34)
>>> person1.name
''
>>> person1.age
34
>>> person1.show_details
<bound method Details.show_details of <__main__.Details instance at 0x10e2e7758>>
>>> 
>>> person1.show_details()
Name :  _
Age  :  34
>>>
>>> person2 = Details("Rob Pike",0)
>>> person2.name
'Rob Pike'
>>> 
>>> person2.age
0
>>> 
>>> person2.show_details()
Name :  Rob Pike
Age  :  _
>>> 
>>> person3 = Details("Rob Pike",-45)
>>> 
>>> person3.name
'Rob Pike'
>>> 
>>> person3.age
-45
>>> 
>>> person3.show_details()
Name :  Rob Pike
Age can't be -ve
>>>
>>> person3.__dict__
{'age': -45, 'name': 'Rob Pike'}
>>>
>>> person3.__dict__.keys()
['age', 'name']
>>>
>>> person3.__dict__.values()
[-45, 'Rob Pike']
>>>
Hullull
fuente
También podemos verificar la callablilty de cada atributo
Visite
-4

__attr__ da la lista de atributos de una instancia.

>>> import requests
>>> r=requests.get('http://www.google.com')
>>> r.__attrs__
['_content', 'status_code', 'headers', 'url', 'history', 'encoding', 'reason', 'cookies', 'elapsed', 'request']
>>> r.url
'http://www.google.com/'
>>>
Vivek
fuente
No siempre funciona Además, escribes __attr__en la descripción pero la usas __attrs__en el código. Ninguno de los dos funcionó para mí (werkzeug.datastructures.FileStorage)
Jonas