Como obter uma lista completa dos métodos e atributos do objeto?

230
dir(re.compile(pattern)) 

não retorna padrão como um dos elementos da lista. Ou seja, ele retorna:

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

De acordo com o manual, ele deve conter

os nomes dos atributos do objeto, os nomes dos atributos da classe e recursivamente os atributos das classes base da classe.

Diz também que

A lista não está necessariamente completa.

Existe uma maneira de obter a lista completa ? Eu sempre assumi que o dir retorna uma lista completa, mas aparentemente não ...

Além disso: existe uma maneira de listar apenas atributos? Ou apenas métodos?

Edit: este é realmente um bug em python -> supostamente é corrigido no ramo 3.0 (e talvez também no 2.6)

Bartosz Radaczyński
fonte
5
o uso dir()ou o módulo de inspeção geralmente é o caminho certo para fazê-lo. Você usou o remódulo apenas como exemplo ou deseja alcançar um objetivo especial?
1
Você tem certeza de que o padrão é realmente mantido como dados depois de compilados? Fiquei com a impressão de que o ponto de compilar um padrão era produzir os autômatos de estados finitos necessários para analisar o padrão fornecido.
Kyle Strand
@hop não pode ser desviado por classes? Por exemplo, eles podem fazer o seu__dir__()
ytpillai
ytpillai: correto, mas apenas em Python 3. Mesmo assim, a questão é, se tal classe cairia no âmbito do "caso geral"

Respostas:

140

Para a lista completa de atributos, a resposta curta é: não. O problema é que os atributos são realmente definidos como os argumentos aceitos pela getattrfunção interna. Como o usuário pode reimplementar __getattr__, permitindo subitamente qualquer tipo de atributo, não há uma maneira genérica possível de gerar essa lista. A dirfunção retorna as chaves no __dict__atributo, ou seja, todos os atributos acessíveis se o __getattr__método não for reimplementado.

Para a segunda pergunta, isso realmente não faz sentido. Na verdade, métodos são atributos que podem ser chamados, nada mais. Você pode filtrar atributos que podem ser chamados e, usando o inspectmódulo, determinar os métodos, métodos ou funções da classe.

PierreBdR
fonte
1
inpect.getmembers (re.compile (pattern)) também não produz um padrão como membro, por isso provavelmente usa dir internamente ... Isso é péssimo!
Bartosz Radaczyński 10/10/08
Eu também poderia usar que pode ser chamado para verificar se eles são métodos, mas isso não é o ponto ... O ponto é que eu posso não dir confiança para voltar até mesmo a lista de atributos que são realmente visíveis publicamente ...
Bartosz Radaczyński
2
inspecionar deve ser "pelo menos tão" confiável quanto dir (). por outro lado, re é um módulo muito complicado
O que você define por "publicamente visível"? Se você quer dizer "pode ​​ser acessado", essa é uma causa perdida pelo motivo exposto. Caso contrário, 'dir' sempre retornará a lista de atributos acessíveis com a implementação padrão do getattr.
31468 PierreBdR
2
dir (minha_classe) retorna algo diferente de minha_classe .__ dict __. keys (). o primeiro também emite os métodos da classe como o init e doc
Juanpi
58

É por isso que o novo __dir__()método foi adicionado no python 2.6

Vejo:

Moe
fonte
Eu recebo este erro: >> dir __ (pyrenderdoc) Traceback (última chamada mais recente): Arquivo "<string>", linha 1, em <module> NameError: name '__dir ' não está definido
Mona Jalal
__dir__ () é um método de objeto, não uma função - por favor leia as ligações na resposta e esta
Moe
Linha única para imprimir todos os atributos e seus valores:pprint({k:getattr(ojb,k) for k in obj.__dir__()})
Czechnology
21

Aqui está uma adição prática às respostas de PierreBdR e Moe:

  • Para Python> = 2.6 e classes de novo estilo , dir()parece suficiente.
  • Para classes de estilo antigo , podemos pelo menos fazer o que um módulo padrão faz para oferecer suporte à conclusão de guias: além de dir()procurar __class__e, em seguida, procurar __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

(O código e a saída do teste são excluídos por questões de concisão, mas basicamente para objetos de estilo novo parecemos ter os mesmos resultados get_object_attrs()que para dir()e para classes de estilo antigo, a principal adição à dir()saída parece ser o __class__atributo.)

ジ ョ ー
fonte
9

Apenas para complementar:

  1. dir()é a ferramenta mais poderosa / fundamental. ( Mais recomendado )
  2. Soluções que dir()não sejam apenas a maneira de lidar com a saída dedir() .

    Listando atributos de segundo nível ou não, é importante fazer a peneiragem sozinho, porque às vezes você pode filtrar os vars internos com os sublinhados principais __, mas às vezes pode precisar da __doc__cadeia de caracteres de documentos.

  3. __dir__()e dir()retorna conteúdo idêntico.
  4. __dict__e dir()são diferentes. __dict__retorna conteúdo incompleto.
  5. IMPORTANTE : __dir__()às vezes pode ser substituído por uma função, valor ou tipo pelo autor para qualquer finalidade.

    Aqui está um exemplo:

    \\...\\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: o descritor __dir__do 'object'objeto precisa de um argumento

    O autor do PyTorch modificou o __dir__()método para algo que requer um argumento. Essa modificação dir()falha.

  6. Se você deseja que um esquema confiável percorra todos os atributos de um objeto, lembre-se de que todos os padrões pitônicos podem ser substituídos e podem não se sustentar , e todas as convenções podem não ser confiáveis.

Quíron
fonte
5

É assim que eu faço, útil para objetos personalizados simples aos quais você continua adicionando atributos:

Dado um objeto criado com obj = type("Obj",(object,),{}), ou simplesmente:

class Obj: pass
obj = Obj()

Adicione alguns atributos:

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

em seguida, para obter um dicionário apenas com os atributos personalizados:

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

# {'name': 'gary', 'age': 32}
mluc
fonte
lista de todos os atributos no Python 3.x: {chave: valor para chave, valor em obj .__ dict __. items () se não for key.startswith ("__")} ['_ declared_fields']. keys ()
above_c_level