Python'daki kötü / yasadışı argüman kombinasyonlarında hangi istisnayı artırmalıyım?


544

Python'da geçersiz argüman kombinasyonlarını belirtmek için en iyi uygulamaları merak ediyordum. Böyle bir işleve sahip olduğunuz birkaç durumla karşılaştım:

def import_to_orm(name, save=False, recurse=False):
    """
    :param name: Name of some external entity to import.
    :param save: Save the ORM object before returning.
    :param recurse: Attempt to import associated objects as well. Because you
        need the original object to have a key to relate to, save must be
        `True` for recurse to be `True`.
    :raise BadValueError: If `recurse and not save`.
    :return: The ORM object.
    """
    pass

Bununla ilgili tek sıkıntı, her paketin kendine özgü, genellikle biraz farklı olmasıdır BadValueError. Java'da var olduğunu biliyorum java.lang.IllegalArgumentException- herkesin BadValueErrorPython'da kendi s'sini yaratacağı anlaşılıyor mu yoksa başka bir tercih edilen yöntem var mı?

Yanıtlar:


608

Daha özel bir istisna gerekmedikçe ValueError'u yükseltirim .

def import_to_orm(name, save=False, recurse=False):
    if recurse and not save:
        raise ValueError("save must be True if recurse is True")

Bunu yapmanın gerçekten bir anlamı yok class BadValueError(ValueError):pass- özel sınıfınız ValueError ile aynıdır , neden bunu kullanmıyorsunuz?


65
> "neden bunu kullanmıyorsun?" - Özgüllük. Belki bazı dış katman "MyValueError" yakalamak istiyorum, ama herhangi bir / tüm "ValueError".
Kevin Little

7
Evet, bu yüzden özgüllük sorununun bir kısmı ValueError'ın başka nerede ortaya çıktığıdır. Callee işlevi bağımsız değişkenlerinizi seviyor, ancak math.sqrt (-1) öğesini dahili olarak çağırıyorsa, bir arayan ValueError değerini yakalayabilir ve bağımsız değişkenlerinin uygunsuz olmasını bekler . Belki de bu durumda mesajı kontrol
edersin

3
Argümanın tuttuğundan emin değilim: birisi arıyorsa math.sqrt(-1), bu yine de düzeltilmesi gereken bir programlama hatasıdır. ValueErrornormal programın yürütülmesinde yakalanmak üzere tasarlanmamıştır ya da türetilebilir RuntimeError.
14'te

2
Hata bağımsız değişkenlerin SAYISI üzerindeyse, değişken sayıda bağımsız değişkene sahip bir işlev için ... örneğin, bağımsız değişkenlerin çift sayıda bağımsız değişken olması gereken bir işlev için, tutarlı olması için bir TypeError öğesi yükseltmelisiniz. Ve a) bir kullanım durumunuz yoksa veya b) başkaları tarafından kullanılmak üzere kütüphaneyi dışa aktarmadığınız sürece kendi sınıfınızı oluşturmayın. Erken işlevsellik kodun ölümüdür.
Erik Aronesty

104

Miras alırım ValueError

class IllegalArgumentError(ValueError):
    pass

Kendi istisnalarınızı oluşturmak bazen daha iyidir, ancak yerleşik olandan miras alın, ki bu da istediğinize olabildiğince yakındır.

Belirli bir hatayı yakalamanız gerekiyorsa, bir adınızın olması yararlı olur.


26
Sınıflar ve özel istisnalar yazmayı bırakın - pyvideo.org/video/880/stop-writing-classes
Hamish Grubijan

40
@HamishGrubijan bu video korkunç. Birisi bir sınıfın iyi bir şekilde kullanılmasını önerdiğinde, sadece "Sınıfları kullanma" yı karıştırdı. Parlak. Sınıflar iyidir. Ama benim sözüme güvenme .
Rob Grant

12
@RobertGrant Hayır, anlamıyorsun. Bu video tam anlamıyla "sınıfları kullanma" ile ilgili değil. Bu, işleri aşırı karmaşıklaştırmamakla ilgilidir.
RayLuo

15
@RayLuo, videonun ne söylediğini akılcı bir şekilde kontrol etmiş olabilirsiniz ve videoyu değişken, mantıklı bir alternatif mesaja dönüştürmüş olabilirsiniz, ancak videonun söylediği şey budur ve çok fazla deneyimi ve sağduyuya sahip olmayan biri gelecektir ile.
Rob Grant

3
Dediğim gibi @SamuelSantana, kimse elini kaldırdığında ve "Peki ya X?" Dediğinde X'in iyi bir fikir olduğu yerde, "başka bir sınıf yapma" dedi. Oldukça açık. Anahtarın denge olduğunu kabul ediyorum; sorun şu ki aslında yaşamak için çok belirsiz :-)
Rob Grant

18

Bence bununla başa çıkmanın en iyi yolu python'un kendisi tarafından ele alınma şeklidir. Python bir TypeError hatası oluşturur. Örneğin:

$ python -c 'print(sum())'
Traceback (most recent call last):
File "<string>", line 1, in <module>
TypeError: sum expected at least 1 arguments, got 0

Junior dev bizim bu sayfayı bir google arama "python istisna yanlış argümanlar" için buldum ve bu soru sorulduğundan beri on yıl içinde bariz (bana) cevabının hiç önerilmediğine şaşırdım.


8
Hiçbir şey beni şaşırtmasa da, işleve aktarılan argümanların bazılarında tür yanlışsa TypeError'ın doğru istisna olduğunu% 100 kabul ediyorum. Değişkenler doğru türdeyse ancak içerikleri ve değerleri anlamlı değilse bir ValueError uygun olur.
user3504575

Bence bu muhtemelen argümanlar için eksik ya da sayılmamış bir şey olsa da, soru doğru verilen argümanlar hakkındadır, ancak verilen argümanın değerini içeren daha yüksek bir soyutlama düzeyinde yanlıştır . Ama aslında ilkini aradığım için, yine de bir oy verin.
Kimse

2
@ User3504575 ve @ Kimse'nin dediği gibi, argümanlar işlev imzasıyla (yanlış konumsal argüman sayısı, yanlış ada sahip anahtar kelime argümanları, yanlış argüman türü) eşleşmezse TypeError kullanılır, ancak işlev çağrıldığında bir ValueError kullanılır imzayla eşleşiyor, ancak bağımsız değişken değerleri geçersiz (ör int('a'). çağrı ). kaynak
goodmami

OP'nin sorusuna "geçersiz argüman kombinasyonları" denildiği için, TypeError uygun görünmektedir, çünkü bu fonksiyon imzasının iletilen argümanlar için yanlış olduğu bir durumdur.
J Bones

Sizin örnek çağıran sum()bir hayır savları tamamen TypeError, ama argüman türlerinin doğru olduğunda OP argüman değerleri "yasadışı" kombinasyonları ile ilgili oldu. Bu durumda, her iki saveve recursebool değerlerden oluşan, ancak eğer recurseolduğunu Trueo zaman saveolmamalıdır False. Bu bir ValueError. Sorunun başlığının bazı yorumlarının cevaplanacağını kabul ediyorum TypeError, ancak sunulan örnek için değil.
goodmami


8

Bu, argümanlarla sorunun ne olduğuna bağlıdır.

Argümanın türü yanlışsa, bir TypeError hatası yükseltin. Örneğin, bu Boole'lardan biri yerine bir dize aldığınızda.

if not isinstance(save, bool):
    raise TypeError(f"Argument save must be of type bool, not {type(save)}")

Bununla birlikte, Python'da nadiren böyle kontroller yaptığımızı unutmayın. Argüman gerçekten geçersizse, daha derin bir işlev muhtemelen bizim için şikayette bulunacaktır. Ve eğer sadece boolean değerini kontrol edersek, belki de bazı kod kullanıcıları daha sonra onu boş olmayan dizelerin her zaman True olduğunu bilerek bir dize besleyecektir. Onu oyuncu kadrosu kurtarabilir.

Bağımsız değişkenler geçersiz değerlere sahipse, ValueError değerini yükseltin. Bu sizin durumunuzda daha uygun görünüyor:

if recurse and not save:
    raise ValueError("If recurse is True, save should be True too")

Veya bu özel durumda, Gerçek bir recurse değerine sahip olmanız, True değerinde bir tasarruf anlamına gelir. Bunu bir hatadan kurtarma olarak değerlendireceğim için, günlükte de şikayet etmek isteyebilirsiniz.

if recurse and not save:
    logging.warning("Bad arguments in import_to_orm() - if recurse is True, so should save be")
    save = True

Bence bu en doğru cevap. Bu açık bir şekilde göz ardı edilmiştir (benimki de dahil olmak üzere 7 oy)
Siu Ching Pong -Asuka Kenji-

-1

Eminim gelen miras ile kabul etmiyorum ValueErroryani belgelerin tesfiri - ValueErroredilmektedir yalnızca ondan devralan veya kendiniz yanlış görünüyor yükselterek ... yerleşikleri tarafından gündeme gerekiyordu.

Yerleşik bir işlem veya işlev doğru türde ancak uygun olmayan bir değere sahip bir bağımsız değişken aldığında ve durum IndexError gibi daha kesin bir istisna ile açıklanmadığında ortaya çıkar.

- ValueError belgeleri


Karşılaştırma google.com/codesearch?q=lang:python+class \ + w \ Hata (\ [e ^] (a * | [^ x] \ w E )): ile google.com/codesearch?q=lang: python + class \ + \ w * Hata (İstisna):
Markus Jarderot

13
Bu bulanıklık basitçe yerleşiklerin onu yükselttiği anlamına gelir ve sadece yerleşiklerin yükseltebileceği anlamına gelmez . Bu örnekte Python belgelerinin dış kütüphanelerin neleri yükselttiği hakkında konuşmak tamamen uygun olmayacaktır.
Ignacio Vazquez-Abrams

5
Gördüğüm her Python yazılımı ValueErrorbu tür bir şey için kullandı , bu yüzden belgelere çok fazla okumaya çalıştığınızı düşünüyorum.
James Bennett

6
Hata, şunu iddia etmek için Google Kod aramalarını kullanacaksak: google.com/codesearch?q=lang%3Apython+raise%5C+ValueError Zope, xen, Django, Mozilla (ve dahil 66.300) değerinde ValueError yükseltme vakası sonuçların ilk sayfasından itibaren). Bir yerleşik istisna uyuyorsa, kullanın ..
dbr

7
Belirtildiği gibi, belgeler belirsizdir. "Yerleşik işlem veya yerleşik işlev alındığında yükseltildi" veya "Bir işlev veya yerleşik işlem alındığında yükseltildi" şeklinde yazılmalıdır. Tabii ki, orijinal amaç ne olursa olsun, mevcut uygulama onu boğdu (@dbr'ın işaret ettiği gibi). Bu yüzden ikinci varyant olarak yeniden yazılmalıdır.
İsimsiz

-1

Markus'un kendi kural dışı durumunuzu reddetme önerisine katılıyorum, ancak kural dışı durum metni, sorunun bağımsız değişken değerleri değil bağımsız değişken listesinde olduğunu açıklığa kavuşturmalıdır. Ben öneririm:

class BadCallError(ValueError):
    pass

Belirli bir arama için gereken anahtar kelime bağımsız değişkenleri eksik olduğunda veya bağımsız değişken değerleri ayrı ayrı geçerli ancak birbiriyle tutarsız olduğunda kullanılır. ValueErrorbelirli bir argüman doğru türde olduğunda ancak aralık dışında olduğunda hala doğru olur.

Bu Python'da standart bir istisna olmamalı mı?

Genel olarak, Python stilinin bir işleve kötü girişleri (arayanın hatası) işlev içindeki kötü sonuçlardan (benim hatam) ayırt etmede biraz daha keskin olmasını istiyorum. Dolayısıyla, bağımsız değişkenlerdeki değer hatalarını yerellerdeki değer hatalarından ayırt etmek için bir BadArgumentError da olabilir.


KeyErrorBulunamadı anahtar kelime için yükseltmek (eksik açık bir anahtar kelime anlamsal olarak **kwargso anahtar eksik olan bir dikte ile özdeş olduğundan ).
cowbert
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.