İstisnayı yükselt - getiri İşlevlerde yok mu?


87

Python'da kullanıcı tanımlı bir işlevde daha iyi uygulama nedir: raisebir istisna veya return None? Örneğin, bir klasördeki en son dosyayı bulan bir işleve sahibim.

def latestpdf(folder):
    # list the files and sort them
    try:
        latest = files[-1]
    except IndexError:
        # Folder is empty.
        return None  # One possibility
        raise FileNotFoundError()  # Alternative
    else:
        return somefunc(latest)  # In my case, somefunc parses the filename

Başka bir seçenek istisna terk ve arayan kodunda ele, ama bu bir başa daha net anlamaya FileNotFoundErrorbir daha IndexError. Yoksa bir istisnayı farklı bir adla yeniden yükseltmek kötü bir biçim mi?



3
Bir istisna oluşturmaya eğilimliyim, bu yüzden çağıran işlevdeki istisnayı ele almak zorunda kalıyorum. Çağıran işlevde çıkışın Yok olup olmadığını kontrol etmeyi unutursam, gizli bir hatam olabilir. Hiçbiri döndürdüyseniz, umarız çağıran işlevdeki bir sonraki satır bir Öznitelik Hatası verir. Bununla birlikte, döndürülen değer bir sözlüğe eklenir ve ardından farklı bir kaynak dosyada 100 işlev çağırırsa, bir AttributeError yükseltilirse, bu değerin neden Yok olduğunu araştırırken eğlenirsiniz.
IceArdor

Genel olarak, özel bir anlamı olan veya bir işlev için birden çok imzası olan değerlerden de kaçınırım (bir dize veya Yok döndürebilir).
IceArdor

Yanıtlar:


92

Bu gerçekten bir anlambilim meselesi. Ne anlama foo = latestpdf(d) geliyor ?

En son dosyanın olmaması tamamen mantıklı mı? O zaman elbette, sadece None döndür.

Her zaman en son dosyayı bulmayı mı bekliyorsunuz? Bir istisna oluşturun. Ve evet, daha uygun bir istisnayı yeniden yükseltmek sorun değil.

Bu herhangi bir dizine uygulanması gereken genel bir işlevse, öncekini yapıp Hiçbiri döndürürüm. Dizin, örneğin, bir uygulamanın bilinen dosya kümesini içeren belirli bir veri dizini anlamına geliyorsa, bir istisna oluştururum.


3
Dikkate alınması gereken bir başka nokta: Bir istisna oluşturuyorsa bir mesaj eklenebilir, ancak bunu geri dönerken yapamayız None.
kawing-chiu

10

Sorunuzu cevaplamadan önce, soruyu sizin için cevaplayabileceği için birkaç öneri yapacağım.

  • Her zaman işlevlerinizi açıklayıcı olarak adlandırın. latestpdfkimse için çok az şey ifade eder, ancak işlevinize baktığınızda latestpdf()en son pdf elde edilir. Adını vermenizi öneririm getLatestPdfFromFolder(folder).

Bunu yaptığım anda neye dönmesi gerektiği belli oldu .. Bir pdf yoksa bir istisna oluşturun. Ama orada daha fazla bekleyin ..

  • İşlevleri açıkça tanımlanmış tutun. Somefuc'un ne yapması gerektiği belli olmadığından ve en son pdf'yi almakla nasıl bir ilişkisi olduğu (görünüşte) açık olmadığından, onu taşımanızı öneririm. Bu, kodu çok daha okunaklı hale getirir.

for folder in folders:
   try:
       latest = getLatestPdfFromFolder(folder)
       results = somefuc(latest)
   except IOError: pass

Bu yardımcı olur umarım!


1
Veya get_latest_pdf_from_folder. Aslında, Pep8: "İşlev adları, okunabilirliği iyileştirmek için gerektiği şekilde alt çizgilerle ayrılmış sözcükler ile küçük harf olmalıdır."
PatrickT

7

Genelde istisnaları dahili olarak işlemeyi tercih ederim (yani, çağrılan işlevin içinde deneyin / dışında, muhtemelen bir Yok döndürür) çünkü python dinamik olarak yazılır. Genel olarak, bunu şu ya da bu şekilde çağıran bir yargı olarak görüyorum, ancak dinamik olarak yazılmış bir dilde, istisnayı arayan kişiye iletmeme lehine ölçekleri değiştiren küçük faktörler vardır:

  1. Fonksiyonunuzu arayan kimse, fırlatılabilecek istisnalar konusunda bilgilendirilmez. Ne tür bir istisna peşinde koştuğunuzu (ve bloklar dışında genel olarak kaçınılması gereken) bilmek bir sanat formu haline gelir.
  2. if val is Nonebiraz daha kolay except ComplicatedCustomExceptionThatHadToBeImportedFromSomeNameSpace. Cidden, from django.core.exceptions import ObjectDoesNotExistgerçekten yaygın bir kullanım durumunu ele almak için tüm django dosyalarımın en üstüne yazmayı hatırlamak zorunda kalmaktan nefret ediyorum . Statik olarak yazılmış bir dünyada, editörün sizin için yapmasına izin verin.

Dürüst olmak gerekirse, bu her zaman bir yargılama çağrısıdır ve tarif ettiğiniz durum, çağrılan işlevin yardımcı olamayacağı bir hata alması, anlamlı bir istisnayı yeniden gündeme getirmek için mükemmel bir nedendir. Tam olarak doğru fikre sahipsiniz, ancak bir istisna olmadıkça, yığın izlemede olduğundan daha anlamlı bilgi sağlayacaktır.

AttributeError: 'NoneType' object has no attribute 'foo'

ki, onda dokuzu, işlenmemiş bir Hiçbiri döndürürseniz arayanın göreceği şeydir, zahmet etmeyin.

(Tüm bunlar, python istisnalarının cause, java'da olduğu gibi varsayılan olarak özniteliklere sahip olmasını dilememe neden oluyor, bu da istisnaları yeni istisnalara geçirmenize izin veriyor, böylece istediğiniz her şeyi yeniden atabilir ve sorunun orijinal kaynağını asla kaybetmezsiniz.)


Olası istisnaların tanımlanmadığı ve bu yüzden yakalanmasının zor olduğu argümanı Python için çok geçerli bir argümandır.
snorberhuis

4

python 3.5 yazarak :

Hiçbiri döndürüldüğünde örnek işlev şu şekilde olacaktır:

def latestpdf(folder: str) -> Union[str, None]

ve bir istisna oluştururken şunlar olacaktır:

def latestpdf(folder: str) -> str 

2. seçenek daha okunabilir ve pitonik görünüyor

(+ daha önce belirtildiği gibi istisnaya yorum ekleme seçeneği.)


5
Union[str, None]olmalıdırOptional[str]
Georgy

2
bir steno, ama haklısınız, daha okunaklı. düzenleme olmadığından her iki seçenek de burada.
Asaf

1
2 potansiyel olarak daha okunabilir ancak (ne yazık ki?) Tip ipuçları bir istisna atılabileceğini göstermez. Son zamanlarda, bir Yok dönüşünü işlemeye zorlandığınızda 1'in daha fazla hata yakalamaya yardımcı olacağını öğrendim.
jonespm

2

Genel olarak, kurtarılamayan felaket bir şey meydana gelirse (yani, işleviniz bağlanılamayan bazı internet kaynaklarıyla ilgileniyorsa) bir istisna atılması gerektiğini söyleyebilirim ve işlevinizin gerçekten bir şey döndürmesi gerekiyorsa Hiçbiri döndürmeniz gerekir. ancak döndürmek için hiçbir şey uygun olmaz (yani, işleviniz bir dizedeki bir alt dizeyi eşleştirmeye çalışırsa "Yok").

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.