Jak uzyskać pełną listę metod i atrybutów obiektu?

230
dir(re.compile(pattern)) 

nie zwraca wzoru jako jednego z elementów list. Mianowicie zwraca:

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

Zgodnie z instrukcją powinien on zawierać

nazwy atrybutów obiektu, nazwy atrybutów jego klasy i rekurencyjnie atrybuty klas podstawowych klasy.

Mówi również, że

Lista niekoniecznie jest kompletna.

Czy istnieje sposób na uzyskanie pełnej listy? Zawsze zakładałem, że reż zwraca pełną listę, ale najwyraźniej nie ...

Ponadto: czy istnieje sposób, aby wyświetlić tylko atrybuty? Czy tylko metody?

Edycja: w rzeczywistości jest to błąd w pythonie -> podobno został naprawiony w gałęzi 3.0 (a być może także w wersji 2.6)

Bartosz Radaczyński
źródło
5
Korzystanie dir()z modułu inspekcji jest na ogół właściwym sposobem. Czy użyłeś remodułu jako przykładu, czy chcesz osiągnąć specjalny cel?
1
Czy na pewno wzorzec jest przechowywany jako dane po skompilowaniu? Miałem wrażenie, że celem kompilacji wzorca było stworzenie automatów skończonych niezbędnych do parsowania podanego wzorca.
Kyle Strand
@hop nie może być omijany przez klasy? Na przykład, mogą zrobić swoje__dir__()
ytpillai
ytpillai: poprawne, ale tylko w Pythonie 3. Mimo to pytanie brzmi, czy taka klasa byłaby objęta „ogólnym przypadkiem”

Odpowiedzi:

140

Dla kompletnej listy atrybutów, krótka odpowiedź brzmi: nie. Problem polega na tym, że atrybuty są faktycznie zdefiniowane jako argumenty akceptowane przez getattrwbudowaną funkcję. Ponieważ użytkownik może ponownie wdrożyć __getattr__, nagle dopuszczając dowolny rodzaj atrybutu, nie ma żadnego możliwego ogólnego sposobu wygenerowania tej listy. dirZwraca klucze w __dict__atrybutu, czyli wszystkie atrybuty dostępne, jeśli __getattr__metoda nie jest przepisany.

W przypadku drugiego pytania to naprawdę nie ma sensu. W rzeczywistości metody są atrybutami, które można wywołać, niczym więcej. Można było jednak filtrować wywoływalne atrybuty i, korzystając z inspectmodułu, określić metody klasowe, metody lub funkcje.

PierreBdR
źródło
1
inpect.getmembers (re.compile (pattern)) również nie daje wzoru jako członka, więc prawdopodobnie używa wewnętrznie katalogu ... To do bani!
Bartosz Radaczyński
Mógłbym również użyć funkcji wywoływania, aby sprawdzić, czy są to metody, ale nie o to chodzi ... Chodzi o to, że nie mogę zaufać reż, aby zwrócił nawet listę atrybutów, które są faktycznie publicznie widoczne ...
Bartosz Radaczyński,
2
inspect ma być „co najmniej tak samo” godny zaufania jak dir (). z drugiej strony, re jest bardzo skomplikowanym modułem
Co definiujesz jako „publicznie widoczny”? Jeśli masz na myśli „można uzyskać dostęp”, oznacza to zgubioną przyczynę z podanego powodu. W przeciwnym razie „dir” zawsze zwraca listę atrybutów dostępnych przy domyślnej implementacji getattr.
PierreBdR 10.10.08
2
dir (moja_klasa) zwraca coś innego niż moja_klasa .__ dict __. keys (). te pierwsze
generują
58

Dlatego nowa __dir__()metoda została dodana w Pythonie 2.6

widzieć:

Moe
źródło
Dostaję ten błąd: >> dir __ (pyrenderdoc) Traceback (ostatnie ostatnie połączenie): Plik „<ciąg>>, wiersz 1, w <module> NameError: nazwa„ __dir ”nie jest zdefiniowana
Mona Jalal
__dir__ () jest metodą na obiekcie, a nie funkcją - proszę przeczytaj linki w odpowiedzi i to
Moe
One-liner do wydrukowania wszystkich atrybutów i ich wartości:pprint({k:getattr(ojb,k) for k in obj.__dir__()})
Czechnology
21

Oto praktyczny dodatek do odpowiedzi PierreBdR i Moe:

  • Wydaje się , że dla Pythona> = 2.6 i klas nowego styludir() .
  • W przypadku klas w starym stylu możemy przynajmniej zrobić to, co robi standardowy moduł w celu obsługi uzupełniania tabulatorów: oprócz tego dir()poszukaj __class__, a następnie przejdź do jego __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

(Kod testowy i dane wyjściowe są usuwane ze względu na zwięzłość, ale w zasadzie dla obiektów w nowym stylu wydaje się, że mamy takie same wyniki get_object_attrs()jak w przypadku dir(), a dla klas w starym stylu głównym dodatkiem do danych dir()wyjściowych wydaje się być __class__atrybut).

ジ ョ ー ジ
źródło
9

Tylko w celu uzupełnienia:

  1. dir()jest najbardziej wydajne / podstawowe narzędzie. ( Najbardziej zalecane )
  2. Rozwiązania inne niż dir()tylko zapewniają sposób radzenia sobie z wynikamidir() .

    Wymieniając atrybuty drugiego poziomu, czy nie, ważne jest, aby przesiać samodzielnie, ponieważ czasami możesz chcieć odfiltrować wewnętrzne zmienne z wiodącymi podkreśleniami __, ale czasami możesz potrzebować __doc__łańcucha dokumentów.

  3. __dir__()i dir()zwraca identyczną treść.
  4. __dict__i dir()są różne. __dict__zwraca niekompletną treść.
  5. WAŻNE : __dir__()może być czasem zastąpione przez funkcję, wartość lub typ przez autora dla dowolnego celu.

    Oto przykład:

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

    Błąd typu: deskryptor __dir__od 'object'obiektu wymaga argumentu

    Autor PyTorch zmodyfikował __dir__()metodę na coś, co wymaga argumentu. Ta modyfikacja powoduje dir()błąd.

  6. Jeśli chcesz, aby niezawodny schemat przechodził przez wszystkie atrybuty obiektu, pamiętaj, że każdy standard Pythona może zostać zastąpiony i może się nie utrzymywać , a każda konwencja może być zawodna.

Chiron
źródło
5

Tak to robię, przydatne dla prostych obiektów niestandardowych, do których ciągle dodajesz atrybuty:

Biorąc pod uwagę obiekt utworzony za pomocą obj = type("Obj",(object,),{})lub po prostu:

class Obj: pass
obj = Obj()

Dodaj niektóre atrybuty:

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

następnie, aby uzyskać słownik z tylko niestandardowymi atrybutami:

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

# {'name': 'gary', 'age': 32}
mluc
źródło
lista wszystkich atrybutów w Pythonie 3.x: {klucz: wartość dla klucza, wartość w obj .__ dict __. items () jeśli nie key.startswith ("__")} ['_
__na_pole