"Hariç" ifadelerinde her zaman bir istisna türü belirtmeli miyim?


96

PyCharm IDE kullanılırken, except:istisna türü olmadan kullanılması, bu istisna cümlesinin olduğu konusunda IDE'den bir hatırlatıcı tetikler Too broad.

Bu tavsiyeyi görmezden gelmeli miyim? Yoksa her zaman istisna türünü belirtmek Pythonic mi?


Bu konuda cevaplardan daha fazlasını öğrenmek istiyorsanız, google yutma istisnaları. Bunların yanında her türlü ilginç yapılacak ve yapılmayacak şeyler yapabilirsiniz. Kod kokuları başka bir şeydir.
Tony Hopkinson

Yanıtlar:


93

Açık bir istisna türü belirtmek neredeyse her zaman daha iyidir. Çıplak bir except:cümle kullanırsanız, yakalamayı bekledikleriniz dışındaki istisnaları yakalayabilirsiniz - bu, hataları gizleyebilir veya beklediğiniz şeyi yapmadıklarında programlarda hata ayıklamayı zorlaştırabilir.

Örneğin, bir veritabanına bir satır ekliyorsanız, satırın zaten var olduğunu gösteren bir istisna yakalamak isteyebilirsiniz, böylece bir güncelleme yapabilirsiniz.

try:
    insert(connection, data)
except:
    update(connection, data)

Çıplak belirtirseniz except:, veritabanı sunucusunun düştüğünü gösteren bir soket hatası da yakalayabilirsiniz. En iyisi, yalnızca nasıl başa çıkacağınızı bildiğiniz istisnaları yakalamaktır - programın istisna noktasında başarısız olması, devam etmekten ancak beklenmedik şekillerde davranmaktan daha iyidir.

Çıplak kullanmak isteyebileceğiniz bir except:durum, bir ağ sunucusu gibi her zaman çalışıyor olmanız gereken bir programın en üst düzeyindedir. Ama sonra, istisnaları kaydetmek için çok dikkatli olmalısınız, aksi takdirde neyin yanlış gittiğini anlamak imkansız olacaktır. Temel olarak, bunu yapan bir programda en fazla bir yer olmalıdır.

Tüm bunların doğal bir sonucu, kodunuzun raise Exception('some message')istemci kodunu kullanmaya zorladığı için except:(ya except Exception:da neredeyse o kadar kötü) asla yapmaması gerektiğidir . Sinyal vermek istediğiniz soruna özel bir istisna tanımlamalısınız (belki ValueErrorveya gibi bazı yerleşik istisna alt sınıflarından miras alabilirsiniz TypeError). Veya belirli bir yerleşik istisna oluşturmalısınız. Bu, kodunuzun kullanıcılarının yalnızca ele almak istedikleri istisnaları yakalama konusunda dikkatli olmalarını sağlar.


7
+1 Çok doğru. Örnekle daha da eğlenceli: except:aynı zamanda yakalar (diğer birçok şeyin yanı sıra) NameErrorve AttributeErrorbu nedenle trybloktaki bir şeyi yanlış yazarsanız (örneğin, "ekleme" işleviniz aslında çağrılır insert_oneçünkü birisi tutarlılığa olması gerektiği kadar değer vermedi) her zaman sessizce dener update().

1
Öyleyse, mevcut arama sitesinin üstüne bir istisna atılmamasını sağlamanız gerektiğinde ne olacak? Yani - fırlatılacağını öngörebildiğim tüm özel istisnaları yakaladım, şimdi eklemem gerekiyor "eğer düşünmediğim bu şey fırlatılırsa, çalışan yürütme bağlamını bitirmeden önce kaydetmem gerekir" (örneğin main())?
Adam Parkin

"Bir dava ..." nın başlangıcında bahsettiğim türden bir durum bu. Bazen buna kesinlikle ihtiyaç duyulur, ancak herhangi bir programın gerçekten bunu yapan tek bir yeri olmalıdır. Ve günlükte neler olduğunu netleştirdiğine dikkat etmelisiniz, aksi takdirde programınızın neden olayı / isteği / her neyse doğru şekilde işlemediğini anlamaya çalışırken sinir bozucu bir zaman geçireceksiniz.
babbageclunk

3
@delnan: Bundan daha kötüsü. except Exception:yakalayacak NameErrorve AttributeErrorçok. Bu except:kadar kötü yapan şey, yakalanmayan işleri yakalamasıdır, örneğin SystemExit(aradığınızda exitveya sys.exitşimdi amaçlanan bir çıkışı engellediniz) ve KeyboardInterrupt(yine, kullanıcı vurursa Ctrl-C, muhtemelen istemezsiniz) sadece onlara inat için koşmaya devam etmek). Sadece ikincisi yakalamak gerçekten mantıklıdır ve açıkça yakalanmalıdır. En azından except Exception:bu ikisinin normal şekilde yayılmasına izin verin.
ShadowRanger

Bu, sürekli olarak katılmadığım tek tüysüz tavsiye. Çoğu zaman, ne tür bir istisna olursa olsun aynı şekilde tepki vermek istersiniz. Bunun, Java'nın ilk dönemlerinden gelen ve asla bırakılmayan belirli bir tavsiyeden kaynaklanan bir engel olduğunu hissediyorum.
enl8enmentnow

39

Tercümanın size verdiği tavsiyeleri görmezden gelmemelisiniz.

Python için PEP-8 Stil Kılavuzundan:

İstisnaları yakalarken, bir bare external: clause kullanmak yerine, mümkün olduğunda belirli istisnalardan bahsedin.

Örneğin, şunu kullanın:

 try:
     import platform_specific_module 
 except ImportError:
     platform_specific_module = None 

Bare exclude: cümlesi, SystemExit ve KeyboardInterrupt istisnalarını yakalayarak, bir programı Control-C ile kesmeyi zorlaştırır ve diğer sorunları gizleyebilir. Program hatalarını işaret eden tüm istisnaları yakalamak istiyorsanız, Exception dışında kullanın: (bare hariç, BaseException hariç :) ile eşdeğerdir.

İyi bir pratik kural, çıplak 'hariç' cümlelerinin kullanımını iki durumla sınırlandırmaktır:

İstisna işleyici, izlemeyi yazdıracak veya günlüğe kaydedecekse; en azından kullanıcı bir hatanın meydana geldiğinin farkında olacaktır. Kodun bazı temizleme çalışması yapması gerekiyorsa, ancak daha sonra istisnanın yükseltme ile yukarı doğru yayılmasına izin verirse. try ... nihayet bu davayı halletmenin daha iyi bir yolu olabilir.



9

Bu Python'a özgü değil.

İstisnaların tüm amacı, sorunu mümkün olduğu kadar ortaya çıktığı yere yakın ele almaktır.

Bu nedenle, istisnai durumlarda sorunu ve çözümü "yan yana" tetikleyebilecek kodu saklarsınız.

Mesele şu ki, bir kod parçası tarafından atılabilecek tüm istisnaları bilemezsiniz. Tek bildiğiniz, eğer istisna bulunmayan bir dosya ise, o zaman onu yakalayabilir ve kullanıcıdan işlevi yapan veya iptal eden bir tane almasını isteyebilirsiniz.

Bunu deneyin yakalamaya koyarsanız, dosya yordamınızda hangi sorun olursa olsun (salt okunur, izinler, UAC, gerçekte bir pdf değil, vb.), Her biri dosyanıza düşecektir catch ve kullanıcınız "ama orada, bu kod saçmalık" diye bağırıyor

Şimdi her şeyi yakalayabileceğiniz birkaç durum var, ancak bilinçli olarak seçilmeleri gerekiyor.

Yakalanırlar, bazı yerel eylemleri geri alırlar (örneğin, bir kaynak oluşturmak veya kilitlemek, (örneğin yazmak için diskte bir dosya açmak), ardından daha yüksek bir düzeyde ilgilenilmek üzere istisnayı tekrar atarsınız)

Diğeri, neden yanlış gittiğini umursamıyorsun. Örneğin baskı. Yazıcınızda bir sorun var, lütfen düzeltin ve bu yüzden uygulamayı sonlandırmayın demek için her yönden bir yakalamaya sahip olabilirsiniz. Buna benzer bir boşuna, eğer kodunuz bir çeşit zamanlama kullanarak bir dizi ayrı görevi yerine getirirse, tüm şeyin ölmesini istemezsiniz, çünkü görevlerden biri başarısız olur.

Not Yukarıdakileri yaparsanız, bir tür istisna günlüğü öneremem, örneğin, son derece yeterli, günlük sonunu yakalamaya çalışın.


Bunun denge ile ilgili olduğunu söyleyebilirim. İstisnayı ondan kurtulmak için yeterince erken ve onunla nereye gideceğinizi bilecek kadar geç yakalamalısınız. Bu nedenle, Java özel durum işleme bu kadar büyük hasara neden olur, çünkü her adımda istisnayı yeniden sarmalamanız gerekir ve bilgileri kaybedersiniz.
dhill

2
"Neden yanlış gittiği umrunda değil" için +1. Bunu, bir URL'den bir tarih / saat ayrıştırdığım tek bir kod satırının çevresinde çeşitli yerlerde kullanıyorum. Üçüncü taraf tarih / saat ayrıştırma kitaplığı, atabileceği tüm istisnaları listelemiyor (standart ValueError'a ek olarak OverflowError ve TypeError buldum, ancak muhtemelen daha fazlası var) ve yine de nedenini gerçekten umursamıyorum bir istisna atıldı, kullanıcıya sadece tarih / saatte bir sorun olduğunu söyleyen makul bir hata mesajı vermek istiyorum.
Michael Rodby

3

Bununla birlikte örneğin Control-C'yi de yakalayacaksınız, bu yüzden tekrar "atmadan" yapmayın. Ancak, bu durumda "nihayet" seçeneğini tercih etmelisiniz.


3

Her zaman gibi catch istemiyorum birçok türü vardır, istisna türünü belirtmek SyntaxError, KeyboardInterrupt, MemoryErrorvb


2
except Exception:yakalamak istemediğimiz yukarıdaki türleri kullanmaktan kaçınır mıyız?
HorseloverFat

except Exceptioniyidir.
Ulrich Eckhardt

4
@HorseloverFat: except Exceptionyakalar SyntaxErrorve MemoryErrorçünkü bu onların temel sınıfıdır. KeyboardInterrupt, SystemExit(tarafından büyütüldü sys.exit()) yakalanmadı (bunlar hemen BaseException alt sınıflarıdır)
jfs

o zaman ideal değilmiş gibi geliyor - daha kesin bir şekilde belirtmek daha iyidir.
HorseloverFat

3

Yazısız dışında kullandığım yerler

  1. hızlı ve kirli prototipleme

Kontrol edilmeyen istisnalar için kodumdaki ana kullanım budur

  1. üst düzey main () işlevi, yakalanmamış her istisnayı günlüğe kaydederim

Her zaman bunu eklerim, böylece üretim kodu yığın izlerini yaymaz

  1. uygulama katmanları arasında

Bunu yapmanın iki yolu var:

  • Bunu yapmanın ilk yolu: daha yüksek seviyeli bir katman daha düşük seviyeli bir işlevi çağırdığında, "en üst" daha düşük seviyeli istisnaları işlemek için çağrıları yazılı istisnalara sarar. Ancak, daha düşük seviyeli fonksiyonlarda işlenmemiş daha düşük seviyeli istisnaları tespit etmek için genel bir hariç ifade ekliyorum.

Bu şekilde tercih ediyorum, hangi istisnaların uygun şekilde yakalanması gerektiğini tespit etmeyi daha kolay buluyorum: Daha yüksek bir seviye tarafından daha düşük seviyeli bir istisna kaydedildiğinde sorunu daha iyi "görüyorum"

  • Bunu yapmanın ikinci yolu: Alt düzey katmanların her üst düzey işlevinin kodu, o belirli katmandaki tüm işlenmemiş istisnaları yakalaması dışında genel olarak sarılır.

Bazı iş arkadaşları, "ait oldukları" alt düzey işlevlerde daha düşük düzeydeki istisnaları koruduğu için bu yolu tercih eder.


-14

Bunu dene:

try:
    #code
except ValueError:
    pass

Cevabı bu bağlantıdan aldım, eğer başka biri bu sorunla karşılaştıysa kontrol edin

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.