Elencare gli attributi di un oggetto


330

C'è un modo per afferrare un elenco di attributi che esistono su istanze di una 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))

Il risultato desiderato è che verrà emesso "multi, str". Voglio che questo veda gli attributi correnti di varie parti di uno script.


75
Praticamente tutti in Python chiamano le loro classi come NewClass. Puoi sfidare le aspettative della gente se usi una convenzione di denominazione simile new_class.
Mike Graham,

Anche se è interattivo per l'uomo e non può essere programmaticamente utilizzato, la help()funzione aiuta a ottenere informazioni su classi, funzioni, builtin, moduli e altro ancora
ytpillai,


Perché nessuna delle risposte è contrassegnata come "Accettata"?
pfabri

Risposte:


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

Potresti anche trovare utile la pprint .


29
Il problema dell'uso di dict è apparso su r / python. qualcuno ha sottolineato che vars (a) equivale a un .__ dict__
David

5
Nel caso qualcuno si stia chiedendo, questo funziona anche su Python 2.7
Ben Mordecai,

8
Per essere precisi, pprint.pprint(a.__dict__)fa una bella stampa sugli attributi.
smci,

1
Sicuramente pprintNON funziona su Python 2.6.
John Greene,

3
Si noti che questo funziona solo per classi definite dall'utente, non per tipi predefiniti o di estensione.
ivan_pozdeev il

173
dir(instance)
# or (same value)
instance.__dir__()
# or
instance.__dict__

Quindi puoi testare con quale tipo è type()o se è un metodo con callable().


dir ha funzionato meglio su classi con attributo sovraccarico get / set
ogurets

dir (esempio) elenca molte cose che probabilmente non ti interessano
jciloa

Questa è stata l'unica funzione che mi ha fornito tutti gli attributi disponibili sul bostonset di dati da sklearn - __dict__era vuoto, quando in realtà c'erano 5 attributi disponibili
Coruscate5


54

Tutte le risposte precedenti sono corrette, hai tre opzioni per quello che stai chiedendo

  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'}

1
vars(foo)ritornafoo.__dict__
Boris

32
>>> ', '.join(i for i in dir(a) if not i.startswith('__'))
'multi, str'

Questo ovviamente stamperà qualsiasi metodo o attributo nella definizione della classe. Puoi escludere metodi "privati" cambiando i.startwith('__')ini.startwith('_')


24

Il modulo inspect fornisce semplici modi per ispezionare un oggetto:

Il modulo inspect offre diverse utili funzioni per ottenere informazioni su oggetti live come moduli, classi, metodi, funzioni, traceback, frame frame e oggetti code.


Usando getmembers()puoi vedere tutti gli attributi della tua classe, insieme al loro valore. Per escludere attributi privati ​​o protetti utilizzare .startswith('_'). Per escludere metodi o funzioni utilizzare 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)

Si noti che ismethod()viene utilizzato sul secondo elemento di ipoiché il primo è semplicemente una stringa (il suo nome).

Offtopic: utilizzare CamelCase per i nomi delle classi.


13

È possibile utilizzare dir(your_object)per ottenere gli attributi egetattr(your_object, your_object_attr) per ottenere i valori

utilizzo:

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

Ciò è particolarmente utile se il tuo oggetto non ha __dict__. In caso contrario, puoi provare anche var (your_object)


11

Si dice spesso che per elencare un elenco completo di attributi è necessario utilizzare dir(). Si noti tuttavia che contrariamente alla credenza popolare dir()non mette in evidenza tutti gli attributi. Ad esempio, potresti notare che __name__potrebbe non essere presente dir()nell'elenco di una classe anche se puoi accedervi dalla classe stessa. Dal documento in poi dir()( Python 2 , Python 3 ):

Poiché dir () viene fornito principalmente come praticità da utilizzare in un prompt interattivo, cerca di fornire un set di nomi interessante più di quanto non cerchi di fornire un set di nomi rigorosamente o coerentemente definito e il suo comportamento dettagliato può cambiare in tutte le versioni. Ad esempio, gli attributi della metaclasse non sono nell'elenco dei risultati quando l'argomento è una classe.

Una funzione come la seguente tende ad essere più completa, sebbene non vi sia alcuna garanzia di completezza poiché l'elenco restituito dir()può essere influenzato da molti fattori tra cui l'implementazione del __dir__()metodo o la personalizzazione __getattr__()o __getattribute__()sulla classe o su uno dei suoi genitori. Vedi i link forniti per maggiori dettagli.

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

9

Per cosa lo vuoi? Potrebbe essere difficile ottenere la risposta migliore senza conoscere l'intento esatto.

  • È quasi sempre meglio farlo manualmente se si desidera visualizzare un'istanza della classe in un modo specifico. Ciò includerà esattamente ciò che vuoi e non includerà ciò che non vuoi, e l'ordine sarà prevedibile.

    Se stai cercando un modo per visualizzare il contenuto di una classe, formatta manualmente gli attributi che ti interessano e forniscili come __str____repr__ metodo o per la tua classe.

  • Se vuoi sapere quali metodi e quali esistono per un oggetto per capire come funziona, usa help . help(a)ti mostrerà un output formattato sulla classe dell'oggetto in base ai suoi argomenti.

  • diresiste per ottenere programmaticamente tutti gli attributi di un oggetto. (L'accesso __dict__fa qualcosa che raggrupperei allo stesso modo ma che non userei me stesso.) Tuttavia, questo potrebbe non includere le cose che desideri e potrebbe includere le cose che non desideri. È inaffidabile e la gente pensa di volerlo molto più spesso di loro.

  • Su una nota un po 'ortogonale, al momento c'è poco supporto per Python 3. Se sei interessato a scrivere software vero, vorrai cose di terze parti come numpy, lxml, Twisted, PIL o qualsiasi numero di framework web che non supportano ancora Python 3 e non hanno in programma di farlo troppo presto. Le differenze tra 2.6 e il ramo 3.x sono piccole, ma la differenza nel supporto delle librerie è enorme.


4
Vorrei solo sottolineare che cinque anni dopo (ora), credo che tutti i moduli di terze parti citati supportino python3. Fonte: python3wos.appspot.com
pzkpfw,

8

C'è più di un modo per farlo:

#! /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 eseguito, questo codice 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$

2
Perché questa risposta è stata sottovalutata? A scopo di debug, dir funziona abbastanza bene!
Dunatotatos,

Funziona abbastanza con Python 2.7.x. Esattamente quello che volevo.
Davidson Lima,

7

Vedi lo script della shell python che è stato eseguito in sequenza, qui otterrai gli attributi di una classe in formato stringa separati da virgola.

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

Sto usando Python 3.4


E se vuoi solo l'elenco può usare solo a.__dict__.keys(). Tuttavia, se vuoi sapere se un oggetto ha un attributo specifico, puoi usarlo hasattr.
berna1111

4

Oltre a queste risposte, includerò una funzione (python 3) per vomitare praticamente l'intera struttura di qualsiasi valore. Utilizza dirper stabilire l'elenco completo dei nomi delle proprietà, quindi utilizza getattrcon ciascun nome. Visualizza il tipo di ogni membro del valore e, quando possibile, visualizza anche l'intero membro:

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

Ora uno qualsiasi dei seguenti dovrebbe dare un'idea:

get_info(None)
get_info('hello')

import numpy
get_info(numpy)
# ... etc.

Wow, è un gioiello!
pfabri

sì, questo è stato un vero toccasana. non sono riuscito a capire perché questo non sia stato possibile decomprimere facilmente questi elenchi e sicuramente un tipo abbastanza ha " slot " di proprietà di tipo "tupla" Ecco il valore degli slot : ["nsname", "hostmaster", "serial", "refresh", "riprova", "scade", "minttl", "ttl"]
Mik R

3

Ottieni gli attributi di un oggetto

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)

Produzione

['__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

1

Come scritto prima dell'uso, è obj.__dict__possibile gestire casi comuni ma alcune classi non hanno l' __dict__attributo e l'uso __slots__(principalmente per l'efficienza della memoria).

esempio per un modo più resiliente di fare questo:

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

l'output di questo codice:

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

Nota 1:
Python è un linguaggio dinamico ed è sempre meglio conoscere le classi da cui provi a ottenere gli attributi poiché anche questo codice può perdere alcuni casi.

Nota2:
questo codice genera solo variabili di istanza che indicano che le variabili di classe non sono fornite. per esempio:

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

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

uscite di codice:

{'path': '/questions'}

Questo codice non stampa l' urlattributo di classe e potrebbe omettere gli attributi di classe desiderati.
A volte potremmo pensare che un attributo sia un membro di istanza ma non lo è e non verrà mostrato usando questo esempio.


2
Una classe può avere __dict__ e __slots__ , quindi probabilmente vorrai provare entrambi piuttosto che solo il dict.
CZ

1
  • L'uso __dict__o vars non funziona perché manca __slots__.
  • L'uso __dict__e __slots__ non funziona perché manca __slots__dalle classi base.
  • L'uso dir non funziona perché include attributi di classe, come metodi o proprietà, nonché gli attributi dell'oggetto.
  • L'uso varsè equivalente all'utilizzo __dict__.

Questo è il migliore che ho:

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

Applichiamo questa funzione a spome semplice classe: classe C: def __init __ (self): print ("creato") i = 42 Perché il tuo codice fornisce un elenco vuoto per tale classe? (Voglio dire se o = C () allora get_attrs (o) è vuoto) Lo ha fatto anche per get_attrs ("mystr")
ged

0
attributes_list = [attribute for attribute in dir(obj) if attribute[0].islower()]

Non funziona con i nomi degli attributi di classe che iniziano con una lettera maiuscola o un singolo trattino basso.
fviktor,

0

Si prega di vedere la seguente esecuzione di script di shell Python in sequenza, fornirà la soluzione dalla creazione della classe all'estrazione dei nomi dei campi delle istanze.

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

Possiamo anche verificare la callablilty di ogni attributes.visit stackoverflow.com/questions/1398022/...
hygull

-4

__attr__ fornisce l'elenco degli attributi di un'istanza.

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

Non sempre funziona. Inoltre, scrivi __attr__nella descrizione ma usi __attrs__nel codice. Né ha funzionato per me (werkzeug.datastructures.FileStorage)
Jonas
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.