Saya mencoba memahami kapan harus menggunakan __getattr__
atau __getattribute__
. The dokumentasi menyebutkan __getattribute__
berlaku untuk kelas gaya baru. Apa itu kelas gaya baru?
python
getattr
getattribute
Yarin
sumber
sumber
Jawaban:
Perbedaan utama antara
__getattr__
dan__getattribute__
itu__getattr__
hanya dipanggil jika atribut tidak ditemukan dengan cara biasa. Ini bagus untuk menerapkan fallback untuk atribut yang hilang, dan mungkin salah satu dari dua yang Anda inginkan.__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.Kelas gaya baru berasal dari
object
, kelas gaya lama adalah mereka yang di Python 2.x tanpa kelas dasar eksplisit. Tetapi perbedaan antara kelas gaya lama dan gaya baru bukanlah yang penting ketika memilih antara__getattr__
dan__getattribute__
.Anda hampir pasti menginginkannya
__getattr__
.sumber
__getattribute__
akan dipanggil untuk setiap akses, dan__getattr__
akan dipanggil untuk waktu yang__getattribute__
dimunculkanAttributeError
. Mengapa tidak menyimpan semuanya dalam satu?__getattribute__
.objec.__getattribute__
memintamyclass.__getattr__
dalam kondisi yang tepat.Mari kita lihat beberapa contoh sederhana dari keduanya
__getattr__
dan__getattribute__
metode sulap.__getattr__
Python akan memanggil
__getattr__
metode setiap kali Anda meminta atribut yang belum ditentukan. Dalam contoh berikut, Hitungan kelas saya tidak__getattr__
metode. Sekarang pada pokoknya ketika saya mencoba mengakses keduanyaobj1.mymin
danobj1.mymax
atribut semuanya berfungsi dengan baik. Tetapi ketika saya mencoba mengaksesobj1.mycurrent
atribut - Python memberi sayaAttributeError: 'Count' object has no attribute 'mycurrent'
Sekarang Count kelas saya memiliki
__getattr__
metode. Sekarang ketika saya mencoba mengaksesobj1.mycurrent
atribut - python mengembalikan saya apa pun yang telah saya terapkan di__getattr__
metode . Dalam contoh saya setiap kali saya mencoba memanggil atribut yang tidak ada, python membuat atribut itu dan mengaturnya ke nilai integer 0.__getattribute__
Sekarang mari kita lihat
__getattribute__
metodenya. Jika Anda memiliki__getattribute__
metode di kelas Anda, python memanggil metode ini untuk setiap atribut terlepas dari apakah itu ada atau tidak. Jadi mengapa kita membutuhkan__getattribute__
metode? Salah satu alasan bagus adalah Anda dapat mencegah akses ke atribut dan membuatnya lebih aman seperti yang ditunjukkan pada contoh berikut.Setiap kali seseorang mencoba mengakses atribut saya yang dimulai dengan substring 'cur' python memunculkan
AttributeError
pengecualian. Kalau tidak, ia mengembalikan atribut itu.Penting: Untuk menghindari rekursi tak terbatas di
__getattribute__
metode, implementasinya harus selalu memanggil metode kelas dasar dengan nama yang sama untuk mengakses atribut apa pun yang diperlukan. Misalnya:object.__getattribute__(self, name)
atausuper().__getattribute__(item)
tidakself.__dict__[item]
PENTING
Jika kelas Anda mengandung kedua getattr dan getAttribute sihir metode kemudian
__getattribute__
disebut pertama. Tetapi jika__getattribute__
memunculkanAttributeError
eksepsi maka eksepsi akan diabaikan dan__getattr__
metode akan dipanggil. Lihat contoh berikut:sumber
__getattribute__
tapi pasti ini bukan. Karena per contoh Anda, semua yang Anda lakukan__getattribute__
adalah meningkatkanAttributeError
pengecualian jika atribut tidak ada di__dict__
objek; tetapi Anda tidak benar-benar membutuhkan ini karena ini adalah implementasi standar__getattribute__
dan infact__getattr__
adalah persis apa yang Anda butuhkan sebagai mekanisme mundur.current
didefinisikan pada instanceCount
(lihat__init__
), jadi cukup naikkanAttributeError
jika atributnya tidak ada apa yang terjadi - itu mengacu pada__getattr__
untuk semua nama yang dimulai dengan 'cur', termasukcurrent
, tetapi jugacurious
,curly
...Ini hanyalah contoh berdasarkan penjelasan Ned Batchelder .
__getattr__
contoh:Dan jika contoh yang sama digunakan dengan
__getattribute__
Anda akan mendapatkan >>>RuntimeError: maximum recursion depth exceeded while calling a Python object
sumber
__getattr__()
Implementasi dunia nyata hanya menerima set terbatas nama atribut yang valid dengan meningkatkanAttributeError
nama atribut yang tidak valid, sehingga menghindari masalah yang halus dan sulit di-debug . Contoh ini tanpa syarat menerima semua nama atribut sebagai valid - penyalahgunaan aneh dan rawan kesalahan__getattr__()
. Jika Anda ingin "kontrol total" atas pembuatan atribut seperti dalam contoh ini, Anda ingin__getattribute__()
.defaultdict
.__getattr__
akan dipanggil sebelum pencarian superclass. Ini tidak masalah untuk subkelas langsungobject
, karena satu-satunya metode yang benar-benar Anda pedulikan ada metode ajaib yang mengabaikan instance, tetapi untuk struktur pewarisan yang lebih kompleks, Anda benar-benar menghapus kemampuan untuk mewarisi apa pun dari induk.Kelas gaya baru diwarisi dari
object
, atau dari kelas gaya baru lain:Kelas gaya lama tidak:
Ini hanya berlaku untuk Python 2 - dalam Python 3 semua hal di atas akan membuat kelas gaya baru.
Lihat 9. Kelas (tutorial Python), NewClassVsClassicClass dan Apa perbedaan antara gaya lama dan kelas gaya baru di Python? untuk detail.
sumber
Kelas-kelas gaya baru adalah kelas-kelas yang mengelompokkan "objek" (langsung atau tidak langsung). Mereka memiliki
__new__
metode kelas sebagai tambahan__init__
dan memiliki perilaku tingkat rendah yang agak lebih rasional.Biasanya, Anda ingin menimpanya
__getattr__
(jika Anda keduanya), jika tidak, Anda akan kesulitan mendukung sintaks "self.foo" dalam metode Anda.Info tambahan: http://www.devx.com/opensource/Article/31482/0/page/4
sumber
Dalam membaca Beazley & Jones PCB, saya menemukan case-use yang eksplisit dan praktis
__getattr__
membantu menjawab bagian "kapan" dari pertanyaan OP. Dari buku:"
__getattr__()
Metodenya seperti catch-all untuk pencarian atribut. Ini adalah metode yang dipanggil jika kode mencoba mengakses atribut yang tidak ada." Kami tahu ini dari jawaban di atas, tetapi dalam resep PCB 8.15, fungsi ini digunakan untuk menerapkan pola desain delegasi . Jika Objek A memiliki atribut Objek B yang mengimplementasikan banyak metode yang ingin didelegasikan Objek A, daripada mendefinisikan ulang semua metode Obyek B di Objek A hanya untuk memanggil metode Objek B, tentukan__getattr__()
metode sebagai berikut:di mana _b adalah nama atribut Object A yang merupakan Object B. Ketika sebuah metode yang didefinisikan pada Object B disebut pada Object A,
__getattr__
metode tersebut akan dipanggil pada akhir rantai pencarian. Ini akan membuat kode lebih bersih juga, karena Anda tidak memiliki daftar metode yang ditentukan hanya untuk mendelegasikan ke objek lain.sumber