Czy występuje problem z wydajnością lub obsługą kodu związany z używaniem
assert
jako części standardowego kodu zamiast używania go wyłącznie do celów debugowania?Jest
assert x >= 0, 'x is less than zero'
lepszy czy gorszy niż
if x < 0: raise Exception, 'x is less than zero'
Czy istnieje też sposób na ustawienie reguły biznesowej, takiej jak
if x < 0 raise error
która jest zawsze sprawdzana bez tegotry/except/finally
, jeśli w dowolnym momencie w całym kodziex
jest mniejszy niż 0, zgłaszany jest błąd, np. Jeśli ustawi sięassert x < 0
na początku funkcji, w dowolnym miejscu funkcji gdziex
staje się mniejszy niż 0 zgłaszany jest wyjątek?
483
assert
.Odpowiedzi:
Aby móc automatycznie zgłaszać błąd, gdy x staje się mniejszy od zera w trakcie funkcji. Możesz użyć deskryptorów klas . Oto przykład:
źródło
Aserty należy stosować do testowania warunków, które nigdy nie powinny się zdarzyć . Celem jest wczesne zawieszenie się w przypadku uszkodzonego stanu programu.
W przypadku błędów, które mogą się zdarzyć, należy stosować wyjątki i prawie zawsze należy tworzyć własne klasy wyjątków .
Na przykład, jeśli piszesz funkcję do odczytu z pliku konfiguracyjnego do pliku
dict
, niewłaściwe formatowanie w pliku powinno wywołać aConfigurationSyntaxError
, podczas gdy możesz,assert
że nie masz zamiaru wrócićNone
.W twoim przykładzie, jeśli
x
wartość jest ustawiona przez interfejs użytkownika lub ze źródła zewnętrznego, najlepszy jest wyjątek.Jeśli
x
jest ustawiony tylko przez własny kod w tym samym programie, przejdź z asercją.źródło
assert
zawiera domniemanieif __debug__
i może zostać zoptymalizowany - jak stwierdza odpowiedź Johna MeeInstrukcje „asert” są usuwane, gdy kompilacja jest zoptymalizowana . Tak, istnieją różnice zarówno wydajnościowe, jak i funkcjonalne.
Jeśli użyjesz
assert
do zaimplementowania funkcji aplikacji, a następnie zoptymalizuj wdrożenie do produkcji, będziesz nękany przez defekty typu „ale to działa”.Zobacz PYTHONOPTIMIZE i -O -OO
źródło
raise
Exception
SuspiciousOperation
Exception
Django
bandit
swój kod, ostrzeże Cię o tym.Cztery cele
assert
Załóżmy, że pracujesz nad 200 000 wierszy kodu z czterema kolegami Alice, Berndem, Carlem i Daphne. Wzywają twój kod, ty wołasz ich kod.
Następnie
assert
ma cztery role :Poinformuj Alice, Bernd, Carl i Daphne, czego oczekuje Twój kod.
Załóżmy, że masz metodę, która przetwarza listę krotek, a logika programu może się zepsuć, jeśli krotki te są niezmienne:
Jest to bardziej wiarygodne niż równoważne informacje w dokumentacji i znacznie łatwiejsze w utrzymaniu.
Poinformuj komputer, czego oczekuje Twój kod.
assert
wymusza prawidłowe zachowanie wywołujących kod. Jeśli twój kod wywołuje kod Alices, a kod Bernda wywołuje twój, to bez tegoassert
, jeśli program ulegnie awarii w kodzie Alices, Bernd może założyć, że to wina Alice, Alice bada i może założyć, że to twoja wina, zbadaj i powiedz Berndowi, że tak naprawdę jego. Dużo straconej pracy.Dzięki zapewnieniom, ktokolwiek pomyli połączenie, szybko zobaczy, że to ich wina, a nie twoja. Alice, Bernd i wszyscy korzystacie. Oszczędza ogromną ilość czasu.
Poinformuj czytelników o swoim kodzie (w tym o sobie), co osiągnął Twój kod w pewnym momencie.
Załóżmy, że masz listę wpisów, a każdy z nich może być czysty (co jest dobre) lub może być smorsh, trale, gullup lub migotać (które wszystkie są niedopuszczalne). Jeśli jest śmierdzący, należy go niesmakować; jeśli jest to prawda, musi być baludoed; jeśli jest to mewa, należy ją wykończyć (a następnie prawdopodobnie również przyspieszyć); jeśli jest migotliwy, musi być ponownie błyśnięty, z wyjątkiem czwartków. Masz pomysł: to skomplikowane rzeczy. Ale końcowym rezultatem jest (lub powinno być), że wszystkie wpisy są czyste. Właściwą rzeczą do zrobienia jest podsumowanie efektu pętli czyszczącej jako
To stwierdzenie oszczędza bólu głowy wszystkim, którzy próbują zrozumieć, co dokładnie osiąga wspaniała pętla. A najczęstszą z tych osób będzie prawdopodobnie ty.
Poinformuj komputer, co osiągnął Twój kod w pewnym momencie.
Jeśli kiedykolwiek zapomnisz wkroczyć do wpisu wymagającego tego po kłusie,
assert
zaoszczędzi ci dzień i uniknie złamania kodu, drogi Daphne, znacznie później.Moim zdaniem
assert
dwa cele dokumentacji (1 i 3) oraz zabezpieczenia (2 i 4) są równie cenne.Informowanie ludzi może być nawet bardziej wartościowe niż informowanie komputera, ponieważ może zapobiec błędom, które
assert
cel ma złapać (w przypadku 1) i wielu późniejszym błędom.źródło
Oprócz innych odpowiedzi twierdzi, że zgłaszają wyjątki, ale tylko błędy AssertionErrors. Z utylitarnego punktu widzenia twierdzenia nie są odpowiednie, gdy potrzebna jest drobnoziarnista kontrola nad tym, które wyjątki wychwytujesz.
źródło
AssertionErrors
, gdy jesteś w porządku z gruboziarnistym. W rzeczywistości nie powinieneś ich łapać.Jedyną rzeczą, która jest naprawdę błędna w tym podejściu, jest to, że trudno jest zrobić bardzo opisowy wyjątek za pomocą instrukcji aser. Jeśli szukasz prostszej składni, pamiętaj, że możesz również zrobić coś takiego:
Innym problemem jest to, że użycie aser do normalnego sprawdzania warunków powoduje, że utrudnienie wyłączenia asercji debugowania odbywa się za pomocą flagi -O.
źródło
Angielskie słowo aser tutaj jest używane w znaczeniu przekleństwa , afirmacji , avow . Nie oznacza to „sprawdź” ani „powinno być” . Oznacza to, że jako programista składasz tutaj oświadczenie pod przysięgą :
Jeśli kod jest poprawny, wykluczając zdenerwowanie pojedynczego zdarzenia , awarie sprzętowe itp., Żadne potwierdzenie nigdy nie zawiedzie . Dlatego nie można wpływać na zachowanie programu dla użytkownika końcowego. Szczególnie twierdzenie nie może zawieść nawet w wyjątkowych warunkach programowych . To się po prostu nigdy nie zdarza. Jeśli tak się stanie, programista powinien zostać za to przełączony.
źródło
Jak już powiedziano wcześniej, należy stosować twierdzenia, gdy kod NIE POWINIEN nigdy osiągnąć punktu, co oznacza, że jest tam błąd. Prawdopodobnie najbardziej użytecznym powodem, dla którego widzę użycie asercji, jest niezmiennik / stan wstępny / postwarunek. Są to coś, co musi być prawdziwe na początku lub na końcu każdej iteracji pętli lub funkcji.
Na przykład funkcja rekurencyjna (2 oddzielne funkcje, więc 1 obsługuje nieprawidłowe dane wejściowe, a druga obsługuje zły kod, ponieważ trudno jest odróżnić rekurencję). Byłoby to oczywiste, gdybym zapomniał napisać instrukcję if, co poszło nie tak.
Te niezmienniki pętli często można przedstawić za pomocą asercji.
źródło
#precondition: n >= 0
twierdzić, może po prostu napisać@precondition(lambda n: n >= 0)
__doc__
Czy występuje problem z wydajnością?
Pamiętaj, aby „sprawić, by działał pierwszy, zanim sprawisz, że będzie działał szybko” .
Bardzo niewiele procent jakiegokolwiek programu jest zwykle istotne dla jego prędkości. Zawsze możesz wykopać lub uprościć,
assert
jeśli okaże się to problemem z wydajnością - i większość z nich nigdy nie będzie.Bądź pragmatyczny :
Załóżmy, że masz metodę, która przetwarza niepustą listę krotek, a logika programu ulegnie awarii, jeśli krotki te nie będą niezmienne. Powinieneś napisać:
Prawdopodobnie jest to w porządku, jeśli twoje listy mają zwykle dziesięć wpisów, ale może to stanowić problem, jeśli mają milion wpisów. Ale zamiast całkowicie odrzucić ten cenny czek, możesz po prostu obniżyć go do poziomu
co jest tanie, ale prawdopodobnie i tak złapie większość faktycznych błędów programu.
źródło
assert(len(listOfTuples)==0 or type(listOfTyples[0])==tuple)
.Cóż, jest to pytanie otwarte i mam dwa aspekty, które chcę dotknąć: kiedy dodawać twierdzenia i jak pisać komunikaty o błędach.
Cel, powód
Aby wytłumaczyć to początkującym - twierdzenia są stwierdzeniami, które mogą wywoływać błędy, ale ich nie złapiecie. I zwykle nie należy ich wychowywać, ale w rzeczywistości czasami i tak się wychowują. Jest to poważna sytuacja, z której kod nie może się zregenerować, co nazywamy „fatalnym błędem”.
Następnie służy do „celów debugowania”, co, choć poprawne, wydaje się bardzo lekceważące. Podoba mi się sformułowanie „deklarowanie niezmienników, które nigdy nie powinno być naruszane”, chociaż działa inaczej na różnych początkujących ... Niektórzy „po prostu to rozumieją”, a inni albo nie znajdują zastosowania, albo zastępują normalne wyjątki, a nawet kontrolować przepływ za jego pomocą.
Styl
W Pythonie
assert
jest instrukcją, a nie funkcją! (pamiętajcie,assert(False, 'is true')
że nie podniesie. Ale odsuwając to na bok:Kiedy i jak napisać opcjonalny „komunikat o błędzie”?
Ten acually dotyczy testów jednostkowych ram, które często mają wiele dedykowanych metod zrobić twierdzeń (
assertTrue(condition)
,assertFalse(condition), assertEqual(actual, expected)
etc.). Często stanowią również sposób skomentowania tego twierdzenia.W kodzie wyrzucającym można obejść się bez komunikatów o błędach.
W niektórych przypadkach do twierdzenia nie można nic dodać:
def dump (coś): assert isinstance (coś, Dumpable) # ...
Ale poza tym wiadomość jest przydatna do komunikacji z innymi programistami (którzy czasami są interaktywnymi użytkownikami twojego kodu, np. W Ipython / Jupyter itp.).
Podaj im informacje, a nie tylko wyciek wewnętrzne szczegóły implementacji.
zamiast:
pisać:
a może nawet:
Wiem, wiem - nie dotyczy to twierdzenia statycznego, ale chcę wskazać wartość informacyjną wiadomości.
Wiadomość negatywna czy pozytywna?
Może to być kontrowersyjne, ale boli mnie czytanie takich rzeczy:
są to dwie sprzeczne rzeczy napisane obok siebie. Więc ilekroć mam wpływ na bazę kodu, naciskam na określenie tego, czego chcemy, używając dodatkowych czasowników, takich jak „musi” i „powinien”, a nie mówiąc, czego nie chcemy.
twierdzić a == b, „a musi być równe b”
Następnie pobieranie
AssertionError: a must be equal to b
jest również czytelne, a instrukcja wygląda logicznie w kodzie. Ponadto możesz coś z niego wyciągnąć bez czytania śledzenia (które czasami może nawet nie być dostępne).źródło
Zarówno stosowanie, jak
assert
i zgłaszanie wyjątków dotyczy komunikacji.Asercje to stwierdzenia o poprawności kodu skierowane do programistów : asercja w kodzie informuje czytelników kodu o warunkach, które muszą zostać spełnione, aby kod był poprawny. Asercja, która nie powiedzie się w czasie wykonywania, informuje programistów, że w kodzie występuje usterka wymagająca naprawy.
Wyjątki stanowią wskazówki dotyczące nietypowych sytuacji, które mogą wystąpić w czasie wykonywania, ale nie mogą być rozwiązane przez dany kod, skierowane do obsługiwanego tam kodu wywołującego. Wystąpienie wyjątku nie oznacza, że w kodzie jest błąd.
Dlatego jeśli uważasz, że wystąpienie określonej sytuacji w czasie wykonywania jest błędem, o którym chciałbyś poinformować programistów („Cześć programisto, ten warunek wskazuje, że gdzieś jest błąd, proszę naprawić kod”.) idź po stwierdzenie. Jeśli asercja sprawdza argumenty wejściowe twojego kodu, zwykle powinieneś dodać do dokumentacji, że twój kod ma „niezdefiniowane zachowanie”, gdy argumenty wejściowe naruszają te warunki.
Jeśli zamiast tego wystąpienie tej samej sytuacji nie jest oznaką błędu w twoich oczach, ale zamiast tego (być może rzadką, ale) możliwą sytuacją, którą Twoim zdaniem powinien zająć się kod klienta, podnieś wyjątek. Sytuacje, w których zgłaszany jest wyjątek, powinny stanowić część dokumentacji odpowiedniego kodu.
Ocena twierdzeń zajmuje trochę czasu. Można je jednak wyeliminować podczas kompilacji. Ma to jednak pewne konsekwencje, patrz poniżej.
Zwykle asercje poprawiają łatwość konserwacji kodu, ponieważ poprawiają czytelność poprzez wyraźne przyjmowanie założeń i regularne ich weryfikowanie w czasie wykonywania. Pomoże to również w łapaniu regresji. Należy jednak pamiętać o jednej kwestii: wyrażenia użyte w asercjach nie powinny mieć skutków ubocznych. Jak wspomniano powyżej, twierdzenia można wyeliminować w czasie kompilacji - co oznacza, że znikną również potencjalne skutki uboczne. Może to - niezamierzenie - zmienić zachowanie kodu.
źródło
Assert ma sprawdzić -
1. poprawny warunek,
2. poprawną instrukcję,
3. prawdziwą logikę;
kodu źródłowego. Zamiast zawieść cały projekt, alarmuje, że coś nie jest odpowiednie w twoim pliku źródłowym.
W przykładzie 1, ponieważ zmienna „str” nie ma wartości null. Więc żadne zgłoszenie ani wyjątek nie zostaną zgłoszone.
Przykład 1:
W przykładzie 2 var 'str' ma wartość NULL. Tak więc ratujemy użytkownika przed pójściem dalej od wadliwego programu za pomocą instrukcji assert .
Przykład 2:
W chwili, gdy nie chcemy debugować i zdajemy sobie sprawę z problemu asercji w kodzie źródłowym. Wyłącz flagę optymalizacji
python -O assertStatement.py
nic nie zostanie wydrukowane
źródło
W IDE, takich jak PTVS, PyCharm,
assert isinstance()
można używać instrukcji Wing, aby umożliwić uzupełnianie kodu dla niektórych niejasnych obiektów.źródło
typing.cast
.Jeśli chodzi o to, co warto, jeśli masz do czynienia z kodem, który polega na
assert
poprawnym działaniu, dodanie następującego kodu zapewni włączenie asercji:źródło