¿Cómo obtener una lista completa de los métodos y atributos del objeto?

230
dir(re.compile(pattern)) 

no devuelve el patrón como uno de los elementos de las listas. A saber, vuelve:

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

Según el manual, se supone que contiene

los nombres de los atributos del objeto, los nombres de los atributos de su clase y recursivamente los atributos de las clases base de su clase.

Dice también que

La lista no está necesariamente completa.

¿Hay alguna manera de obtener la lista completa ? Siempre supuse que dir devuelve una lista completa pero aparentemente no ...

Además: ¿hay alguna manera de enumerar solo los atributos? ¿O solo métodos?

Editar: esto es en realidad un error en python -> supuestamente se soluciona en la rama 3.0 (y quizás también en 2.6)

Bartosz Radaczyński
fuente
55
usar dir()o el módulo de inspección es generalmente la forma correcta de hacerlo. ¿Usó el remódulo solo como ejemplo o desea alcanzar un objetivo especial?
1
¿Estás seguro de que el patrón se mantiene como datos una vez compilados? Tenía la impresión de que el objetivo de compilar un patrón era producir los autómatas de estado finito necesarios para analizar el patrón dado.
Kyle Strand
¿@hop no puede ser evitado por las clases? Por ejemplo, pueden hacer su__dir__()
ytpillai
ytpillai: correcto, pero solo en Python 3. Aun así, la pregunta es si tal clase caería dentro del "caso general"

Respuestas:

140

Para la lista completa de atributos, la respuesta corta es: no. El problema es que los atributos se definen realmente como los argumentos aceptados por la getattrfunción incorporada. Como el usuario puede reimplementar __getattr__, permitiendo de repente cualquier tipo de atributo, no hay una forma genérica posible de generar esa lista. La dirfunción devuelve las claves en el __dict__atributo, es decir, todos los atributos accesibles si el __getattr__método no se vuelve a implementar.

Para la segunda pregunta, realmente no tiene sentido. En realidad, los métodos son atributos invocables, nada más. Sin embargo, podría filtrar los atributos invocables y, utilizando el inspectmódulo, determinar los métodos, métodos o funciones de la clase.

PierreBdR
fuente
1
inpect.getmembers (re.compile (pattern)) tampoco produce un patrón como miembro, por lo que probablemente usa dir internamente ... ¡Esto apesta!
Bartosz Radaczyński
También podría usar invocables para verificar si son métodos, pero ese no es el punto ... El punto es que no puedo confiar en que dir devuelva incluso la lista de atributos que en realidad son visibles públicamente ...
Bartosz Radaczyński
2
inspeccionar debe ser "al menos tan" confiable como dir (). Por otro lado, re es un módulo muy complicado
¿Qué define por "públicamente visible"? Si quiere decir "se puede acceder", entonces esa es una causa perdida por la razón dada. De lo contrario, 'dir' siempre devuelve la lista de atributos accesibles con la implementación predeterminada de getattr.
PierreBdR
2
dir (my_class) devuelve algo diferente a my_class .__ dict __. keys (). el primero también muestra los métodos de la clase como init y doc
JuanPi
58

Es por eso __dir__()que se ha agregado el nuevo método en Python 2.6

ver:

Moe
fuente
Recibo este error: >> dir __ (pyrenderdoc) Traceback (última llamada más reciente): Archivo "<cadena>", línea 1, en <módulo> NameError: el nombre '__dir ' no está definido
Mona Jalal
__dir__ () es un método sobre un objeto, no una función - lea los enlaces en la respuesta y esto
Moe
One-liner para imprimir todos los atributos y sus valores:pprint({k:getattr(ojb,k) for k in obj.__dir__()})
Czechnology
21

Aquí hay una adición práctica a las respuestas de PierreBdR y Moe:

  • Para Python> = 2.6 y clases de estilo nuevo , dir()parece ser suficiente.
  • Para las clases de estilo antiguo , al menos podemos hacer lo que hace un módulo estándar para admitir la finalización de pestañas: además de dir()buscar __class__y luego buscar __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
    

(El código de prueba y la salida se eliminan por brevedad, pero básicamente para los objetos de estilo nuevo parece que tenemos los mismos resultados get_object_attrs()que para dir(), y para las clases de estilo antiguo, la principal adición a la dir()salida parece ser el __class__atributo).

ジ ョ ー ジ
fuente
9

Solo para complementar:

  1. dir()Es la herramienta más poderosa / fundamental. ( Más recomendado )
  2. Las soluciones que dir()no sean simplemente proporcionan su forma de manejar la salida dedir() .

    Listando los atributos de segundo nivel o no, es importante hacer el cribado usted mismo, porque a veces es posible que desee tamizar los vars internos con guiones bajos __, pero a veces es posible que necesite la __doc__cadena de documentación.

  3. __dir__()y dir()devuelve contenido idéntico.
  4. __dict__y dir()son diferentes __dict__devuelve contenido incompleto.
  5. IMPORTANTE : __dir__()el autor a veces puede sobrescribirlo con una función, valor o tipo para cualquier propósito.

    Aquí hay un ejemplo:

    \\...\\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: el descriptor __dir__del 'object'objeto necesita un argumento

    El autor de PyTorch modificó el __dir__()método a algo que requiere un argumento. Esta modificación hace dir()fallar.

  6. Si desea un esquema confiable para atravesar todos los atributos de un objeto, recuerde que cada estándar pitónico puede ser anulado y puede no cumplirse , y cada convención puede no ser confiable.

Quirón
fuente
5

Así es como lo hago, útil para objetos personalizados simples a los que sigues agregando atributos:

Dado un objeto creado con obj = type("Obj",(object,),{}), o simplemente:

class Obj: pass
obj = Obj()

Agrega algunos atributos:

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

luego, para obtener un diccionario con solo los atributos personalizados:

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

# {'name': 'gary', 'age': 32}
mluc
fuente
lista de todos los atributos en Python 3.x: {clave: valor para clave, valor en obj .__ dict __. items () si no es key.startswith ("__")} ['_ declaración_campos']. keys ()
above_c_level