Saya mencoba memahami perbedaan antara __getattr__
dan __getattribute__
, bagaimanapun, saya gagal dalam hal itu.
The jawaban ke Stack Overflow pertanyaan Perbedaan antara __getattr__
vs__getattribute__
mengatakan:
__getattribute__
dipanggil sebelum melihat atribut sebenarnya pada objek, dan bisa jadi sulit untuk diterapkan dengan benar. Anda dapat berakhir dalam rekursi tak terbatas dengan sangat mudah.
Saya sama sekali tidak tahu apa artinya itu.
Kemudian dikatakan:
Anda hampir pasti menginginkannya
__getattr__
.
Mengapa?
Saya membaca bahwa jika __getattribute__
gagal, __getattr__
dipanggil. Jadi mengapa ada dua metode berbeda melakukan hal yang sama? Jika kode saya mengimplementasikan kelas gaya baru, apa yang harus saya gunakan?
Saya mencari beberapa contoh kode untuk menghapus pertanyaan ini. Saya telah menggunakan Google untuk yang terbaik dari kemampuan saya, tetapi jawaban yang saya temukan tidak membahas masalah secara menyeluruh.
Jika ada dokumentasi, saya siap membacanya.
sumber
Jawaban:
Beberapa dasar dulu.
Dengan objek, Anda harus berurusan dengan atributnya. Biasanya kita lakukan
instance.attribute
. Terkadang kita perlu lebih banyak kontrol (ketika kita tidak tahu nama atribut sebelumnya).Sebagai contoh,
instance.attribute
akan menjadigetattr(instance, attribute_name)
. Dengan menggunakan model ini, kita bisa mendapatkan atribut dengan memasok atribut_name sebagai string.Penggunaan
__getattr__
Anda juga bisa memberi tahu kelas bagaimana menangani atribut yang tidak dikelola secara eksplisit dan melakukannya melalui
__getattr__
metode.Python akan memanggil metode ini setiap kali Anda meminta atribut yang belum ditentukan, sehingga Anda dapat menentukan apa yang harus dilakukan dengannya.
Kasus penggunaan klasik:
Peringatan dan penggunaan
__getattribute__
Jika Anda perlu menangkap setiap atribut terlepas dari apakah itu ada atau tidak , gunakan
__getattribute__
saja. Perbedaannya adalah bahwa__getattr__
hanya dipanggil untuk atribut yang tidak benar-benar ada. Jika Anda menetapkan atribut secara langsung, merujuk atribut itu akan mengambilnya tanpa menelepon__getattr__
.__getattribute__
disebut sepanjang waktu.sumber
getattr(instance, attribute_name)
." Bukankah seharusnya begitu__getattribute__(instance, attribute_name)
?getattr
adalah fungsi bawaan .getattr(foo, 'bar')
setara denganfoo.bar
.__getattr__
hanya akan dipanggil jika sudah ditentukan, karena tidak diwarisi dariobject
__getattribute__
dipanggil setiap kali akses atribut terjadi.Ini akan menyebabkan rekursi yang tak terbatas. Pelakunya di sini adalah garis
return self.__dict__[attr]
. Mari kita berpura-pura (Sudah cukup dekat dengan kebenaran) bahwa semua atribut disimpanself.__dict__
dan tersedia dengan namanya. Garismencoba mengakses
a
atribut darif
. Ini panggilanf.__getattribute__('a')
.__getattribute__
kemudian mencoba memuatself.__dict__
.__dict__
adalah atributself == f
dan panggilan pythonf.__getattribute__('__dict__')
yang lagi mencoba mengakses atribut'__dict__
'. Ini adalah rekursi yang tak terbatas.Jika
__getattr__
telah digunakan sebagai gantinyaf
memilikia
atribut.f.b
), maka itu tidak akan dipanggil untuk menemukan__dict__
karena sudah ada dan__getattr__
dipanggil hanya jika semua metode lain untuk menemukan atribut telah gagal .Cara 'benar' untuk menulis menggunakan kelas di atas
__getattribute__
adalahsuper(Foo, self).__getattribute__(attr)
mengikat__getattribute__
metode superclass 'terdekat' (secara formal, kelas berikutnya dalam Metode Resolution Order kelas, atau MRO) ke objek saat iniself
dan kemudian memanggilnya dan memungkinkan yang melakukan pekerjaan.Semua masalah ini dihindari dengan menggunakan
__getattr__
yang memungkinkan Python melakukan hal yang normal sampai atribut tidak ditemukan. Pada titik itu, Python menyerahkan kontrol ke__getattr__
metode Anda dan membiarkannya menghasilkan sesuatu.Perlu juga dicatat bahwa Anda dapat mengalami rekursi tak terbatas
__getattr__
.Saya akan meninggalkan yang itu sebagai latihan.
sumber
Saya pikir jawaban lain telah melakukan pekerjaan yang bagus untuk menjelaskan perbedaan antara
__getattr__
dan__getattribute__
, tetapi satu hal yang mungkin tidak jelas adalah mengapa Anda ingin menggunakannya__getattribute__
. Hal yang paling keren__getattribute__
adalah bahwa pada dasarnya memungkinkan Anda untuk membebani titik saat mengakses kelas. Ini memungkinkan Anda untuk menyesuaikan cara atribut diakses di tingkat rendah. Sebagai contoh, misalkan saya ingin mendefinisikan kelas di mana semua metode yang hanya mengambil argumen sendiri diperlakukan sebagai properti:Dan dari interpreter interaktif:
Tentu saja ini adalah contoh konyol dan Anda mungkin tidak akan pernah mau melakukan ini, tetapi ini menunjukkan kekuatan yang bisa Anda dapatkan dari mengganti
__getattribute__
.sumber
Saya telah melalui penjelasan luar biasa dari yang lain. Namun, saya menemukan jawaban sederhana dari blog ini Python Sihir Metode dan
__getattr__
. Semua yang berikut berasal dari sana.Dengan menggunakan
__getattr__
metode ajaib, kita dapat mencegat pencarian atribut yang tidak ada dan melakukan sesuatu agar tidak gagal:Tetapi jika atribut itu ada,
__getattr__
tidak akan dipanggil:__getattribute__
mirip dengan__getattr__
, dengan perbedaan penting yang__getattribute__
akan mencegat SETIAP pencarian atribut, tidak masalah apakah atribut itu ada atau tidak.Dalam contoh itu,
d
objek sudah memiliki nilai atribut. Tetapi ketika kami mencoba mengaksesnya, kami tidak mendapatkan nilai yang diharapkan asli ("Python"); kami hanya mendapatkan apa pun yang__getattribute__
dikembalikan. Ini berarti bahwa kita hampir kehilangan atribut nilai; itu telah menjadi "tidak terjangkau".sumber