Bagaimana cara mendapatkan daftar lengkap metode dan atribut objek?

230
dir(re.compile(pattern)) 

tidak mengembalikan pola sebagai salah satu elemen daftar. Yaitu mengembalikan:

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

Menurut manual, seharusnya berisi

nama atribut objek, nama atribut kelasnya, dan secara rekursif atribut dari kelas dasar kelasnya.

Dikatakan juga itu

Daftar ini belum tentu lengkap.

Apakah ada cara untuk mendapatkannya? daftar lengkap ? Saya selalu berasumsi bahwa dir mengembalikan daftar lengkap tetapi ternyata itu tidak ...

Juga: apakah ada cara untuk membuat daftar hanya atribut? Atau hanya metode?

Sunting: ini sebenarnya adalah bug dalam python -> yang seharusnya diperbaiki di cabang 3.0 (dan mungkin juga di 2.6)

Bartosz Radaczyński
sumber
5
menggunakan dir()atau memeriksa modul biasanya merupakan cara yang tepat untuk melakukannya. Apakah Anda menggunakan remodul hanya sebagai contoh atau Anda ingin mencapai tujuan khusus?
1
Apakah Anda yakin bahwa pola tersebut benar-benar disimpan sebagai data yang pernah dikompilasi? Saya mendapat kesan bahwa titik penyusunan pola adalah untuk menghasilkan automata keadaan terbatas yang diperlukan untuk menguraikan pola yang diberikan.
Kyle Strand
@hop tidak bisa dir dikesampingkan oleh kelas? Misalnya, mereka dapat membuat on__dir__()
ytpillai
ytpillai: benar, tetapi hanya dalam Python 3. Meski begitu, pertanyaannya adalah, apakah kelas seperti itu akan jatuh di bawah "kasus umum"

Jawaban:

140

Untuk lengkap daftar atribut, jawaban singkatnya adalah: tidak ada. Masalahnya adalah bahwa atribut sebenarnya didefinisikan sebagai argumen yang diterima oleh getattrfungsi bawaan. Karena pengguna dapat menerapkan kembali __getattr__, tiba-tiba memungkinkan segala jenis atribut, tidak ada cara umum yang mungkin untuk menghasilkan daftar itu. The dirmengembalikan fungsi kunci dalam __dict__atribut, yaitu semua atribut diakses jika __getattr__metode tidak reimplemented.

Untuk pertanyaan kedua, itu tidak masuk akal. Sebenarnya, metode adalah atribut yang bisa dipanggil, tidak lebih. Anda dapat memfilter atribut callable, dan, menggunakan inspectmodul menentukan metode kelas, metode atau fungsi.

PierreBdR
sumber
1
inpect.getmembers (re.compile (pola)) juga tidak menghasilkan pola sebagai anggota, jadi mungkin menggunakan dir secara internal ... Ini payah!
Bartosz Radaczyński
Saya juga bisa menggunakan callable untuk memeriksa apakah itu metode, tapi bukan itu intinya ... Intinya saya tidak bisa percaya dir untuk mengembalikan bahkan daftar atribut yang benar-benar terlihat secara publik ...
Bartosz Radaczyński
2
memeriksa dimaksudkan untuk "setidaknya sebagai" dapat dipercaya sebagai dir (). di sisi lain, re adalah modul yang sangat rumit
Apa yang Anda definisikan dengan "terlihat oleh publik"? Jika maksud Anda "dapat diakses", maka itu adalah alasan yang hilang karena alasan yang diberikan. Kalau tidak, 'dir' selalu mengembalikan daftar atribut yang dapat diakses dengan implementasi default getattr.
PierreBdR
2
dir (my_class) mengembalikan sesuatu yang berbeda dari my_class .__ dict __. keys (). yang pertama juga menampilkan metode kelas seperti init dan doc
JuanPi
58

Itu sebabnya __dir__()metode baru telah ditambahkan dalam python 2.6

Lihat:

Moe
sumber
Saya mendapatkan kesalahan ini: >> dir __ (pyrenderdoc) Traceback (panggilan terakhir terakhir): File "<string>", baris 1, dalam <module> NameError: name '__dir ' tidak ditentukan
Mona Jalal
__dir__ () adalah metode pada objek, bukan fungsi - harap baca tautan dalam jawaban dan ini
Moe
One-liner untuk mencetak semua atribut dan nilainya:pprint({k:getattr(ojb,k) for k in obj.__dir__()})
Czechnology
21

Berikut ini adalah tambahan praktis untuk jawaban PierreBdR dan Moe:

  • Untuk Python> = 2.6 dan kelas gaya baru , dir()tampaknya sudah cukup.
  • Untuk kelas gaya lama , kita setidaknya bisa melakukan apa yang modul standar lakukan untuk mendukung penyelesaian tab: selain itu dir(), cari __class__, lalu lanjutkan untuk __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

(Kode uji dan output dihapus untuk singkatnya, tetapi pada dasarnya untuk objek gaya baru kita tampaknya memiliki hasil yang sama get_object_attrs()seperti untuk dir(), dan untuk kelas gaya lama tambahan utama pada dir()output tampaknya menjadi __class__atribut.)

ジ ョ ー ジ
sumber
9

Hanya untuk melengkapi:

  1. dir()adalah alat yang paling kuat / mendasar. ( Paling direkomendasikan )
  2. Solusi selain dir()hanya menyediakan cara mereka menangani keluarandir() .

    Mendaftar atribut level 2 atau tidak, penting untuk melakukan penyaringan sendiri, karena kadang-kadang Anda mungkin ingin menyaring vars internal dengan garis bawah utama __, tetapi kadang-kadang Anda mungkin perlu __doc__doc-string.

  3. __dir__()dan dir()mengembalikan konten yang identik.
  4. __dict__dan dir()berbeda. __dict__mengembalikan konten yang tidak lengkap.
  5. PENTING : __dir__()terkadang dapat ditimpa dengan fungsi, nilai atau tipe, oleh penulis untuk tujuan apa pun.

    Berikut ini sebuah contoh:

    \\...\\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: descriptor __dir__dari 'object'objek membutuhkan argumen

    Penulis PyTorch memodifikasi __dir__()metode menjadi sesuatu yang membutuhkan argumen. Modifikasi ini membuat dir()gagal.

  6. Jika Anda ingin skema yang dapat diandalkan untuk melintasi semua atribut dari suatu objek, ingatlah bahwa setiap standar pythonic dapat ditimpa dan mungkin tidak berlaku , dan setiap konvensi mungkin tidak dapat diandalkan.

Chiron
sumber
5

Ini adalah cara saya melakukannya, berguna untuk objek kustom sederhana yang Anda tambahkan atribut:

Diberikan objek yang dibuat dengan obj = type("Obj",(object,),{}), atau hanya dengan:

class Obj: pass
obj = Obj()

Tambahkan beberapa atribut:

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

lalu, untuk mendapatkan kamus dengan hanya atribut khusus:

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

# {'name': 'gary', 'age': 32}
mluc
sumber
daftar semua atribut dalam Python 3.x: {key: value for key, value in obj .__ dict __. items () jika bukan key.startswith ("__")} ['_
decl_fields