Listar atributos de um objeto

330

Existe uma maneira de pegar uma lista de atributos que existem nas instâncias de uma classe?

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

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

O resultado desejado é que "multi, str" será exibido. Eu quero que isso veja os atributos atuais de várias partes de um script.

MadSc13ntist
fonte
75
Praticamente todo mundo no Python nomeia suas classes NewClass. Você pode desafiar as expectativas das pessoas se usar uma convenção de nomes como new_class.
Mike Graham
Mesmo que seja humano interativo e não pode ser programaticamente usadas, help()função de ajuda para obter informações sobre as classes, funções, builtins, módulos, e mais
ytpillai
1
Relevante: stackoverflow.com/questions/1398022/…
sancho.s ReinstateMonicaCellio 24/04
Por que nenhuma das respostas está marcada como 'Aceito'?
pfabri

Respostas:

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'])

Você também pode achar útil a impressão .


fonte
29
A questão do uso do dict acabou de aparecer no r / python. alguém apontou que vars (a) é equivalente a uma .__ dict__
David
5
No caso de alguém está se perguntando, isso funciona em Python 2.7, bem
Ben Mordecai
8
Para ser específico, pprint.pprint(a.__dict__)imprime bastante os atributos.
smci 27/08/16
1
Definitivamente isso pprintNÃO funciona no Python 2.6.
John Greene
3
Observe que isso funciona apenas para classes definidas pelo usuário, não para tipos internos ou de extensão.
ivan_pozdeev
173
dir(instance)
# or (same value)
instance.__dir__()
# or
instance.__dict__

Em seguida, você pode testar qual é o tipo type()ou se é um método callable().

Htechno
fonte
dir funcionou melhor em classes com sobrecarregado atributo get / set
ogurets
dir (exemplo) enumera uma série de coisas que você provavelmente não está interessado em
jciloa
Esta foi a única função que me tem todos os atributos disponíveis no bostonconjunto de dados do sklearn - __dict__estava vazio, quando na verdade havia 5 atributos disponíveis
Coruscate5
72

vars(obj) retorna os atributos de um objeto.

rohithpr
fonte
53

Todas as respostas anteriores estão corretas, você tem três opções para o que está perguntando

  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
fonte
1
vars(foo)retornafoo.__dict__
Boris
32
>>> ', '.join(i for i in dir(a) if not i.startswith('__'))
'multi, str'

Obviamente, isso imprimirá quaisquer métodos ou atributos na definição de classe. Você pode excluir métodos "particulares" alterando i.startwith('__')parai.startwith('_')

SilentGhost
fonte
24

O módulo de inspeção fornece maneiras fáceis de inspecionar um objeto:

O módulo inspecionar fornece várias funções úteis para ajudar a obter informações sobre objetos ativos, como módulos, classes, métodos, funções, rastreamentos, objetos de quadro e objetos de código.


Usando getmembers()você pode ver todos os atributos da sua classe, juntamente com o valor deles. Para excluir atributos privados ou protegidos, use .startswith('_'). Para excluir métodos ou funções, use inspect.ismethod()ou 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)

Observe que ismethod()é usado no segundo elemento de, ipois o primeiro é simplesmente uma string (seu nome).

Offtopic: Use CamelCase para nomes de classes.

Paradoxo de Fermi
fonte
13

Você pode usar dir(your_object)para obter os atributos e getattr(your_object, your_object_attr)obter os valores

uso:

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

Isso é particularmente útil se o seu objeto não tiver __dict__. Se não for esse o caso, você pode tentar var (your_object) também

Jason Angel
fonte
11

É frequentemente mencionado que para listar uma lista completa de atributos que você deve usar dir(). Observe, porém, que, ao contrário da crença popular dir(), não traz todos os atributos. Por exemplo, você pode perceber que __name__pode estar faltando na dir()listagem de uma classe, mesmo que você possa acessá-la na própria classe. No documento dir()( Python 2 , Python 3 ):

Como dir () é fornecido principalmente como uma conveniência para uso em um prompt interativo, ele tenta fornecer um conjunto interessante de nomes mais do que tenta fornecer um conjunto de nomes definido de forma rigorosa ou consistente, e seu comportamento detalhado pode mudar entre as versões. Por exemplo, os atributos de metaclasse não estão na lista de resultados quando o argumento é uma classe.

Uma função como a seguinte tende a ser mais completa, embora não haja garantia de completude, pois a lista retornada por dir()pode ser afetada por muitos fatores, incluindo a implementação do __dir__()método ou a personalização __getattr__()ou __getattribute__()na classe ou em um de seus pais. Consulte os links fornecidos para obter mais detalhes.

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
fonte
9

O que você quer isso? Pode ser difícil obter a melhor resposta sem conhecer sua intenção exata.

  • É quase sempre melhor fazer isso manualmente, se você deseja exibir uma instância da sua classe de uma maneira específica. Isso incluirá exatamente o que você deseja e não o que não deseja, e o pedido será previsível.

    Se você estiver procurando uma maneira de exibir o conteúdo de uma classe, formate manualmente os atributos de seu interesse e forneça-o como método __str__ou __repr__para sua classe.

  • Se você quiser aprender sobre quais métodos e esses existem para um objeto entender como ele funciona, use help. help(a)mostrará uma saída formatada sobre a classe do objeto com base em suas doutrinas.

  • direxiste para obter programaticamente todos os atributos de um objeto. (Acessar __dict__faz algo que eu agruparia da mesma forma, mas que não usaria a mim mesmo.) No entanto, isso pode não incluir o que você deseja e pode incluir o que não deseja. Não é confiável e as pessoas pensam que querem isso com muito mais frequência do que desejam.

  • Em uma nota um tanto ortogonal, há muito pouco suporte para o Python 3 no momento atual. Se você estiver interessado em escrever um software real, precisará de coisas de terceiros, como numpy, lxml, Twisted, PIL ou qualquer número de estruturas da web que ainda não suportem o Python 3 e que não tenham planos para isso tão cedo. As diferenças entre a ramificação 2.6 e 3.x são pequenas, mas a diferença no suporte à biblioteca é enorme.

Mike Graham
fonte
4
Gostaria apenas de salientar que cinco anos depois (agora), acredito que todos os módulos de terceiros mencionados por você suportam python3. Fonte: python3wos.appspot.com
pzkpfw
8

Há mais de uma maneira de fazer isso:

#! /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) )

Quando executado, esse código produz:

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$
user1928764
fonte
2
Por que esta resposta foi reduzida? Para fins de depuração, dir funciona muito bem!
Dunatotatos
Funciona bastante com o Python 2.7.x. Exatamente o que eu queria.
Davidson Lima
7

Por favor, veja o script shell python que foi executado em sequência; aqui você obterá os atributos de uma classe no formato string separados por vírgula.

>>> 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/>

Eu estou usando python 3.4

Lokesh kumar
fonte
E se você quiser apenas a lista pode usar apenas a.__dict__.keys(). No entanto, se você quiser saber se um objeto tem um atributo específico, você pode usar hasattr.
berna1111
4

Além dessas respostas, incluirei uma função (python 3) para espalhar virtualmente toda a estrutura de qualquer valor. Ele usa dirpara estabelecer a lista completa de nomes de propriedades e depois usa getattrcom cada nome. Ele exibe o tipo de cada membro do valor e, quando possível, também exibe o membro inteiro:

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

Agora, qualquer um dos seguintes deve fornecer informações:

get_info(None)
get_info('hello')

import numpy
get_info(numpy)
# ... etc.
Gershom
fonte
Uau, isso é uma jóia!
pfabri
Sim, isso foi um salva-vidas. não consegui descobrir por que isso não poderia descompactar facilmente essas listas e com certeza o tipo tem propriedade " slots " do tipo "tuple" Aqui está o valor dos slots : ["nsname", "hostmaster", "serial", "refresh", "tentar novamente", "expira", "minttl", "ttl"]
Mik R
3

Obter atributos de um 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)

Resultado

['__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
Abençoado
fonte
1

Conforme escrito antes de usar, obj.__dict__pode lidar com casos comuns, mas algumas classes não têm o __dict__atributo e o uso __slots__(principalmente para eficiência de memória).

exemplo para uma maneira mais resiliente de fazer isso:

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))

saída deste código:

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

Nota1:
Python é uma linguagem dinâmica e é sempre melhor conhecer as classes das quais você está tentando obter os atributos, pois mesmo esse código pode perder alguns casos.

Nota2:
esse código gera apenas variáveis ​​de instância, o que significa que variáveis ​​de classe não são fornecidas. por exemplo:

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

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

saídas de código:

{'path': '/questions'}

Este código não imprime o urlatributo de classe e pode omitir os atributos de classe desejados.
Às vezes, podemos pensar que um atributo é um membro da instância, mas não é e não será mostrado usando este exemplo.

ShmulikA
fonte
2
Uma classe pode ter __dict__ e __slots__ , portanto, você provavelmente quer tentar as duas, e não apenas o ditado.
cz
1
  • Usando __dict__ou vars não funciona porque perde __slots__.
  • Usar __dict__e __slots__ não funciona porque perde as __slots__classes base.
  • O uso dir não funciona porque inclui atributos de classe, como métodos ou propriedades, além dos atributos do objeto.
  • Usar varsé equivalente a usar __dict__.

Este é o melhor que tenho:

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
fonte
Vamos aplicar esta função para gerar uma classe simples: classe C: def __init __ (self): print ("created") i = 42 Por que seu código fornece uma lista vazia para essa classe? (Quer dizer, caso o = C (), em seguida, get_attrs (O) está vazia) Também fez para get_attrs ( "mystr")
GED
0
attributes_list = [attribute for attribute in dir(obj) if attribute[0].islower()]
shammerw0w
fonte
Ele não funciona com nomes de atributos de classe começando com uma letra maiúscula ou um sublinhado único.
Feviktor 12/09/16
0

Por favor, veja a seguinte execução de script de shell do Python em sequência; ela fornecerá a solução desde a criação da classe até a extração dos nomes de campo das instâncias.

>>> 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']
>>>
hygull
fonte
Também podemos verificar a capacidade de chamada de cada atributo.visit stackoverflow.com/questions/1398022/…
hygull
-4

__attr__ fornece a lista de atributos de uma instância.

>>> 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
fonte
Nem sempre funciona. Além disso, você escreve __attr__na descrição, mas usa __attrs__no código. Nem funcionou para mim (werkzeug.datastructures.FileStorage)
Jonas