Come ottenere un elenco completo dei metodi e degli attributi dell'oggetto?


230
dir(re.compile(pattern)) 

non restituisce pattern come uno degli elementi delle liste. Vale a dire che ritorna:

['__copy__', '__deepcopy__', 'findall', 'finditer', 'match', 'scanner', 'search', 'split', 'sub', 'subn']

Secondo il manuale, dovrebbe contenere

i nomi degli attributi dell'oggetto, i nomi degli attributi della sua classe e ricorsivamente gli attributi delle classi base della sua classe.

Lo dice anche quello

L'elenco non è necessariamente completo.

C'è un modo per ottenere l' elenco completo ? Ho sempre pensato che dir restituisse un elenco completo ma a quanto pare non ...

Inoltre: esiste un modo per elencare solo gli attributi? O solo metodi?

Modifica: questo è in realtà un bug in Python -> presumibilmente è stato risolto nel ramo 3.0 (e forse anche in 2.6)


5
l'utilizzo dir()o il modulo inspect è generalmente il modo giusto per farlo. Hai usato il remodulo solo come esempio o vuoi raggiungere un obiettivo speciale?

1
Sei sicuro che il modello sia effettivamente conservato come dati una volta compilato? Avevo l'impressione che il punto di compilare un modello fosse quello di produrre gli automi a stati finiti necessari per analizzare il modello dato.
Kyle Strand

@hop non può essere evitato dalle classi? Ad esempio, possono fare il loro__dir__()
ytpillai l'

ytpillai: corretto, ma solo in Python 3. Tuttavia, la domanda è se tale classe rientrerebbe nel "caso generale"

Risposte:


140

Per l' elenco completo degli attributi, la risposta breve è: no. Il problema è che gli attributi sono effettivamente definiti come argomenti accettati dalla getattrfunzione incorporata. Poiché l'utente può reimplementarsi __getattr__, consentendo improvvisamente qualsiasi tipo di attributo, non esiste un modo generico per generare tale elenco. La dirfunzione restituisce le chiavi __dict__dell'attributo, ovvero tutti gli attributi accessibili se il __getattr__metodo non viene reimplementato.

Per la seconda domanda, non ha davvero senso. In realtà, i metodi sono attributi richiamabili, niente di più. È possibile filtrare gli attributi richiamabili e, utilizzando il inspectmodulo, determinare i metodi, i metodi o le funzioni della classe.


1
inpect.getmembers (re.compile (pattern)) non produce neanche pattern come membro, quindi probabilmente usa dir internamente ... Questo fa schifo!
Bartosz Radaczyński,

Potrei anche usare il callable per verificare se sono metodi, ma non è questo il punto ... Il punto è che non posso fidarmi di dir per restituire anche l'elenco di attributi che sono effettivamente pubblicamente visibili ...
Bartosz Radaczyński,

2
inspect è pensato per essere "almeno altrettanto affidabile" come dir (). d'altra parte, re è un modulo molto complicato

Cosa definisci "visibile pubblicamente"? Se intendi "accessibile", questa è una causa persa per il motivo indicato. Altrimenti, 'dir' restituisce sempre l'elenco di attributi accessibili con l'implementazione predefinita di getattr.
PierreBdR,

2
dir (my_class) restituisce qualcosa di diverso da my_class .__ dict __. keys (). il primo produce anche metodi della classe come init e doc
JuanPi

58

Ecco perché il nuovo __dir__()metodo è stato aggiunto in Python 2.6

vedere:


Ottengo questo errore: >> dir __ (pyrenderdoc) Traceback (ultima chiamata più recente): File "<string>", linea 1, in <module> NameError: il nome '__dir ' non è definito
Mona Jalal

__dir__ () è un metodo sull'oggetto, non una funzione - leggi i link nella risposta e questo
Moe

One-liner per evidenziare tutti gli attributi e i loro valori:pprint({k:getattr(ojb,k) for k in obj.__dir__()})
Czechnology

21

Ecco un'aggiunta pratica alle risposte di PierreBdR e Moe:

  • Per Python> = 2.6 e le classi di nuovo stile , dir()sembra essere sufficiente.
  • Per le classi di vecchio stile , possiamo almeno fare ciò che fa un modulo standard per supportare il completamento delle schede: oltre a dir(), cercare __class__, e poi andare per il suo __bases__:

    # code borrowed from the rlcompleter module
    # tested under Python 2.6 ( sys.version = '2.6.5 (r265:79063, Apr 16 2010, 13:09:56) \n[GCC 4.4.3]' )
    
    # or: from rlcompleter import get_class_members
    def get_class_members(klass):
        ret = dir(klass)
        if hasattr(klass,'__bases__'):
            for base in klass.__bases__:
                ret = ret + get_class_members(base)
        return ret
    
    
    def uniq( seq ): 
        """ the 'set()' way ( use dict when there's no set ) """
        return list(set(seq))
    
    
    def get_object_attrs( obj ):
        # code borrowed from the rlcompleter module ( see the code for Completer::attr_matches() )
        ret = dir( obj )
        ## if "__builtins__" in ret:
        ##    ret.remove("__builtins__")
    
        if hasattr( obj, '__class__'):
            ret.append('__class__')
            ret.extend( get_class_members(obj.__class__) )
    
            ret = uniq( ret )
    
        return ret

(Il codice di test e l'output vengono eliminati per brevità, ma fondamentalmente per gli oggetti di nuovo stile sembriamo avere gli stessi risultati di get_object_attrs()come per dir(), e per le classi di vecchio stile, l'aggiunta principale dir()all'output sembra essere l' __class__attributo.)


9

Solo per integrare:

  1. dir()è lo strumento più potente / fondamentale. ( Più consigliato )
  2. Soluzioni diverse dal dir()semplice fornire il modo di gestire l'output didir() .

    Elencando gli attributi di 2 ° livello o meno, è importante fare il setaccio da soli, perché a volte potresti voler setacciare i var interni con i trattini bassi __, ma a volte potresti aver bisogno della __doc__doc-string.

  3. __dir__()e dir()restituisce contenuto identico.
  4. __dict__e dir()sono diversi. __dict__restituisce contenuti incompleti.
  5. IMPORTANTE : a __dir__()volte può essere sovrascritto da una funzione, valore o tipo, dall'autore per qualsiasi scopo.

    Ecco un esempio:

    \\...\\torchfun.py in traverse(self, mod, search_attributes)
    445             if prefix in traversed_mod_names:
    446                 continue
    447             names = dir(m)
    448             for name in names:
    449                 obj = getattr(m,name)

    TypeError: descrittore __dir__di 'object'oggetto deve un argomento

    L'autore di PyTorch ha modificato il __dir__()metodo in qualcosa che richiede un argomento. Questa modifica dir()fallisce.

  6. Se vuoi che uno schema affidabile attraversi tutti gli attributi di un oggetto, ricorda che ogni standard pitonico può essere ignorato e potrebbe non essere valido , e ogni convenzione potrebbe essere inaffidabile.


5

Ecco come lo faccio, utile per semplici oggetti personalizzati a cui continui ad aggiungere attributi:

Dato un oggetto creato con obj = type("Obj",(object,),{})o semplicemente:

class Obj: pass
obj = Obj()

Aggiungi alcuni attributi:

obj.name = 'gary'
obj.age = 32

quindi, per ottenere un dizionario con solo gli attributi personalizzati:

{key: value for key, value in obj.__dict__.items() if not key.startswith("__")}

# {'name': 'gary', 'age': 32}

elenco di tutti gli attributi in Python 3.x: {chiave: valore per chiave, valore in obj .__ dict __. items () se non key.startswith ("__")} ['_ dichiarato_fields']. keys ()
above_c_level
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.