Saya sedang menulis wadah saya sendiri, yang perlu memberikan akses ke kamus di dalam oleh panggilan atribut. Penggunaan khas wadah akan seperti ini:
dict_container = DictContainer()
dict_container['foo'] = bar
...
print dict_container.foo
Saya tahu mungkin bodoh menulis sesuatu seperti ini, tapi itulah fungsi yang harus saya sediakan. Saya sedang berpikir untuk mengimplementasikan ini dengan cara berikut:
def __getattribute__(self, item):
try:
return object.__getattribute__(item)
except AttributeError:
try:
return self.dict[item]
except KeyError:
print "The object doesn't have such attribute"
Saya tidak yakin apakah percobaan bersarang / kecuali blok adalah praktik yang baik sehingga cara lain adalah dengan menggunakan hasattr()
dan has_key()
:
def __getattribute__(self, item):
if hasattr(self, item):
return object.__getattribute__(item)
else:
if self.dict.has_key(item):
return self.dict[item]
else:
raise AttributeError("some customised error")
Atau untuk menggunakan salah satunya dan satu coba tangkap blok seperti ini:
def __getattribute__(self, item):
if hasattr(self, item):
return object.__getattribute__(item)
else:
try:
return self.dict[item]
except KeyError:
raise AttributeError("some customised error")
Opsi mana yang paling pythonic dan elegan?
if 'foo' in dict_container:
. Amin.Jawaban:
Contoh pertama Anda baik-baik saja. Bahkan dokumen Python resmi merekomendasikan gaya ini yang dikenal sebagai EAFP .
Secara pribadi, saya lebih suka menghindari bersarang saat tidak perlu:
PS.
has_key()
telah lama tidak digunakan dalam Python 2. Gunakanitem in self.dict
sebagai gantinya.sumber
return object.__getattribute__(item)
tidak benar dan akan menghasilkan aTypeError
karena jumlah argumen yang salah disahkan. Seharusnya sebaliknyareturn object.__getattribute__(self, item)
.from None
artinya di baris terakhir?Sementara di Jawa itu memang praktik yang buruk untuk menggunakan Pengecualian untuk kontrol aliran (terutama karena pengecualian memaksa jvm untuk mengumpulkan sumber daya ( lebih lanjut di sini )), dengan Python Anda memiliki 2 prinsip penting: Mengetik Bebek dan EAFP . Ini pada dasarnya berarti bahwa Anda didorong untuk mencoba menggunakan objek seperti yang Anda pikir akan berhasil, dan menangani ketika hal-hal tidak seperti itu.
Singkatnya satu-satunya masalah adalah kode Anda mendapatkan terlalu banyak indentasi. Jika Anda menyukainya, coba sederhanakan beberapa sarang seperti yang disarankan lqc
sumber
Untuk contoh spesifik Anda, Anda sebenarnya tidak perlu membuat sarang. Jika ekspresi di
try
blok berhasil, fungsi akan kembali, jadi kode apa pun setelah seluruh blok coba / kecuali hanya akan dijalankan jika upaya pertama gagal. Jadi Anda bisa melakukannya:Bersarang mereka tidak buruk, tetapi saya merasa seperti membiarkannya rata membuat struktur lebih jelas: Anda secara berurutan mencoba serangkaian hal dan mengembalikan yang pertama yang berhasil.
Secara kebetulan, Anda mungkin ingin memikirkan apakah Anda benar-benar ingin menggunakannya
__getattribute__
daripada di__getattr__
sini. Menggunakan__getattr__
akan menyederhanakan hal-hal karena Anda akan tahu bahwa proses pencarian atribut normal telah gagal.sumber
Hanya hati-hati - dalam hal ini pertama kali
finally
disentuh TAPI dilewati juga.sumber
finally
blok dieksekusia(0)
, tetapi hanya orangtuafinally-return
yang dikembalikan.Menurut pendapat saya ini akan menjadi cara yang paling Pythonic untuk menanganinya, meskipun dan karena itu membuat pertanyaan Anda diperdebatkan. Perhatikan bahwa ini mendefinisikan
__getattr__()
alih-alih__getattribute__()
karena melakukan itu berarti hanya berurusan dengan atribut "khusus" yang disimpan dalam kamus internal.sumber
except
blok dapat memberikan hasil membingungkan dengan Python 3. Itu karena (per PEP 3134) Python 3 melacak pengecualian pertama (theKeyError
) sebagai "konteks" dari pengecualian kedua (theAttributeError
), dan jika mencapai tingkat atas, ia akan mencetak traceback yang mencakup kedua pengecualian. Ini bisa membantu ketika pengecualian kedua tidak diharapkan, tetapi jika Anda sengaja menaikkan pengecualian kedua, itu tidak diinginkan. Untuk Python 3.3, PEP 415 menambahkan kemampuan untuk menekan konteks dengan menggunakanraise AttributeError("whatever") from None
.KeyError
menjadiAttributeError
dan menunjukkan bahwa ini apa yang terjadi di traceback akan berguna dan yang sesuai.__getattr__
memunculkan pengecualian, bug tersebut mungkin salah ketik pada akses atribut, bukan bug implementasi dalam kode kelas saat ini. Menampilkan pengecualian sebelumnya karena konteks dapat mengacaukannya. Dan bahkan ketika Anda menekan konteks denganraise Whatever from None
, Anda masih bisa mendapatkan pengecualian sebelumnya jika perlu viaex.__context__
.__getattribute__()
.Dalam Python lebih mudah untuk meminta maaf daripada izin. Jangan memusingkan penanganan pengecualian bersarang.
(Selain itu,
has*
hampir selalu menggunakan pengecualian di bawah penutup.)sumber
Menurut dokumentasi , lebih baik untuk menangani beberapa pengecualian melalui tuple atau seperti ini:
sumber
Contoh yang bagus dan sederhana untuk percobaan bersarang / kecuali adalah sebagai berikut:
Sekarang coba berbagai kombinasi dan Anda akan mendapatkan hasil yang benar:
[Tentu saja kita punya numpy jadi kita tidak perlu membuat fungsi ini]
sumber
Satu hal yang saya ingin hindari adalah menaikkan pengecualian baru saat menangani yang lama. Itu membuat pesan kesalahan membingungkan untuk dibaca.
Misalnya, dalam kode saya, saya awalnya menulis
Dan saya mendapat pesan ini.
Yang saya inginkan adalah ini:
Itu tidak memengaruhi bagaimana pengecualian ditangani. Di salah satu blok kode, KeyError akan ditangkap. Ini hanya masalah mendapatkan poin gaya.
sumber
from None
, untuk poin gaya yang lebih banyak lagi . :)Jika coba-kecuali-akhirnya bersarang di dalam akhirnya blok, hasil dari "anak" akhirnya dipertahankan. Saya belum menemukan expaination resmi, tetapi cuplikan kode berikut menunjukkan perilaku ini dalam Python 3.6.
sumber
Saya tidak berpikir itu masalah menjadi pythonic atau elegan. Ini masalah mencegah pengecualian sebanyak yang Anda bisa. Pengecualian dimaksudkan untuk menangani kesalahan yang mungkin terjadi dalam kode atau acara yang tidak dapat Anda kendalikan. Dalam hal ini Anda memiliki kontrol penuh ketika memeriksa apakah suatu item adalah atribut atau dalam kamus, jadi hindari pengecualian bersarang dan tetap dengan upaya kedua Anda.
sumber