Jaka jest lepsza praktyka w funkcji zdefiniowanej przez użytkownika w Pythonie: raise
wyjątek czy return None
? Na przykład mam funkcję, która znajduje najnowszy plik w folderze.
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
Inną opcją jest pozostawienie wyjątku i obsłużenie go w kodzie wywołującego, ale wydaje mi się, że łatwiej jest zająć się a FileNotFoundError
niż IndexError
. A może to zła forma ponownego zgłaszania wyjątku z inną nazwą?
python
exception-handling
parcydarks
źródło
źródło
Odpowiedzi:
To naprawdę kwestia semantyki. Co to
foo = latestpdf(d)
znaczy ?Czy to całkiem rozsądne, że nie ma najnowszego pliku? W takim razie po prostu zwróć Brak.
Czy spodziewasz się, że zawsze znajdziesz najnowszy plik? Podnieś wyjątek. I tak, ponowne zgłoszenie bardziej odpowiedniego wyjątku jest w porządku.
Jeśli jest to tylko ogólna funkcja, która ma mieć zastosowanie do dowolnego katalogu, zrobiłbym pierwszą i zwrócił Brak. Jeśli katalog ma być np. Określonym katalogiem danych, który zawiera znany zestaw plików aplikacji, zgłosiłbym wyjątek.
źródło
None
.Zanim odpowiem na Twoje pytanie, przedstawię kilka sugestii, ponieważ może to odpowiedzieć na pytanie za Ciebie.
latestpdf
niewiele znaczy dla nikogo, ale przeglądanie funkcjilatestpdf()
powoduje wyświetlenie najnowszego pliku PDF. Sugerowałbym, żebyś to nazwałgetLatestPdfFromFolder(folder)
.Jak tylko to zrobiłem, stało się jasne, co powinien zwrócić. Jeśli nie ma pliku PDF, zgłoś wyjątek. Ale poczekaj tam więcej ...
for folder in folders: try: latest = getLatestPdfFromFolder(folder) results = somefuc(latest) except IOError: pass
Mam nadzieję że to pomoże!
źródło
get_latest_pdf_from_folder
. Rzeczywiście, Pep8: „Nazwy funkcji powinny być pisane małymi literami, aw razie potrzeby wyrazy oddzielone podkreśleniem”.Zwykle wolę obsługiwać wyjątki wewnętrznie (tj. Try / except wewnątrz wywoływanej funkcji, prawdopodobnie zwracając None), ponieważ python jest wpisywany dynamicznie. Ogólnie uważam to za wezwanie do oceny w taki czy inny sposób, ale w dynamicznie wpisywanym języku istnieją małe czynniki, które przechylają szalę na korzyść nieprzekazywania wyjątku dzwoniącemu:
if val is None
jest trochę łatwiejsze niżexcept ComplicatedCustomExceptionThatHadToBeImportedFromSomeNameSpace
. Poważnie, nienawidzę konieczności pamiętania o wpisywaniufrom django.core.exceptions import ObjectDoesNotExist
na górze wszystkich moich plików django tylko po to, aby obsłużyć naprawdę powszechny przypadek użycia. W świecie wpisywanym statycznie, pozwól edytorowi zrobić to za Ciebie.Szczerze mówiąc, zawsze jest to wezwanie do oceny, a sytuacja, którą opisujesz, w której wywoływana funkcja otrzymuje błąd, którego nie może pomóc, jest doskonałym powodem do ponownego zgłoszenia wyjątku, który ma znaczenie. Masz dokładny właściwy pomysł, ale chyba, że jesteś wyjątkiem, dostarczysz bardziej znaczących informacji w śladzie stosu niż
AttributeError: 'NoneType' object has no attribute 'foo'
co dziewięć razy na dziesięć zobaczy dzwoniący, jeśli zwrócisz nieobsłużone Brak, nie przejmuj się.
(Wszystko to sprawia, że chciałbym, aby wyjątki w Pythonie miały
cause
domyślnie atrybuty, tak jak w java, co pozwala przekazywać wyjątki do nowych wyjątków, aby można było wrzucić wszystko, co chcesz, i nigdy nie stracić pierwotnego źródła problemu).źródło
z pisaniem w Pythonie 3.5 :
Przykładowa funkcja zwracająca None będzie:
def latestpdf(folder: str) -> Union[str, None]
a podczas zgłaszania wyjątku będzie:
def latestpdf(folder: str) -> str
opcja 2 wydaje się bardziej czytelna i pytoniczna
(+ opcja dodania komentarza do wyjątku, jak wspomniano wcześniej).
źródło
Union[str, None]
powinno byćOptional[str]
Ogólnie rzecz biorąc, powiedziałbym, że wyjątek powinien zostać wyrzucony, jeśli wydarzyło się coś katastrofalnego, z którego nie można odzyskać (tj. Twoja funkcja zajmuje się jakimś zasobem internetowym, z którym nie można się połączyć) i powinieneś zwrócić None, jeśli twoja funkcja naprawdę powinna coś zwrócić ale nic nie byłoby właściwe do zwrócenia (np. „Brak”, jeśli funkcja próbuje na przykład dopasować podłańcuch w ciągu).
źródło