đ» Bruke assertion
#
MĂ„let med defensive programming er Ă„ prĂžve Ă„ maksimere pĂ„liteligheten og den generelle kvaliteten til et stykke programvare. For oss betyr dette at vi bĂžr ta skritt for Ă„ hĂ„ndtere uventede inputverdier i koden vĂ„r, og Ă„ gi nyttige feilmeldinger som gir meningsfull veiledning til brukeren nĂ„r et program flagger et unntak. Vi kan ta skritt mot Ă„ skrive mer pĂ„litelig programvare ved Ă„ bruke en nyttig funksjon i Python: âAssertionsâ.
Assertions/PĂ„stander#
Assertions/PÄstander er en mÄte Ä hevde, eller sikre, at verdiene som brukes i skriptene dine kommer til Ä passe til det koden gjÞr. La oss starte med Ä vurdere funksjonen convert_kph_ms
som konverterer vindhastigheter fra kilometer i timen til meter per sekund. Vi kan definere og bruke funksjonen vÄr i cellen under.
def convert_kmt_ms(speed):
"""Konverterer hastighet fra km/t til m/s"""
return speed * 1000 / 3600
wind_speed_km = 9
wind_speed_ms = convert_kmt_ms(wind_speed_km)
print(f"En vindhastighet pÄ {wind_speed_km} km/t er {wind_speed_ms} m/s.")
En vindhastighet pÄ 9 km/t er 2.5 m/s.
Alt dette virker greit, men du vil kanskje sÞrge for at verdiene for vindhastigheten ikke er negative tall, siden hastigheten ganske enkelt er stÞrrelsen pÄ vindhastigheten, som alltid skal vÊre positiv eller null. Vi kan hÄndheve denne betingelsen ved Ä legge til en pÄstand til funksjonen vÄr.
def convert_kmt_ms(speed):
"""Konverterer hastighet fra km/t til m/s"""
assert speed >= 0.0
return speed * 1000 / 3600
wind_speed_km = 9
wind_speed_ms = convert_kmt_ms(wind_speed_km)
print(f"En vindhastighet pÄ {wind_speed_km} km/t er {wind_speed_ms} m/s.")
En vindhastighet pÄ 9 km/t er 2.5 m/s.
OK, sÄ alt fungerer fortsatt ved bruk av en positiv verdi, men hva skjer hvis vi nÄ gir en negativ verdi for vindhastigheten? La oss sjekke!
wind_speed_km = -27
wind_speed_ms = convert_kmt_ms(wind_speed_km)
print(f"En vindhastighet pÄ {wind_speed_km} km/t er {wind_speed_ms} m/s.")
---------------------------------------------------------------------------
AssertionError Traceback (most recent call last)
Cell In[3], line 2
1 wind_speed_km = -27
----> 2 wind_speed_ms = convert_kmt_ms(wind_speed_km)
4 print(f"En vindhastighet pÄ {wind_speed_km} km/t er {wind_speed_ms} m/s.")
Cell In[2], line 3, in convert_kmt_ms(speed)
1 def convert_kmt_ms(speed):
2 """Konverterer hastighet fra km/t til m/s"""
----> 3 assert speed >= 0.0
4 return speed * 1000 / 3600
AssertionError:
OK, sÄ nÄ fÄr vi en AssertionError
nÄr en negativ verdi er gitt. Denne AssertionError
er produsert pÄ grunn av assert
-setningen vi skrev inn i funksjonsdefinisjonen. Hvis betingelsen som er oppfĂžrt etter assert
er usann, oppstÄr en AssertionError
.
Dette er en klar forbedring, men det ville vÊre mye bedre Ä gi brukeren litt informasjon om hvorfor denne pÄstanden eksisterer. Heldigvis kan vi gjÞre dette ganske enkelt ved Ä legge til litt tekst etter pÄstandsbetingelsen.
def convert_kmt_ms(speed):
"""Konverterer hastighet fra km/t til m/s"""
assert speed >= 0.0, "Vindhastighetsverdier mÄ vÊre positive eller null"
return speed * 1000 / 3600
wind_speed_km = -27
wind_speed_ms = convert_kmt_ms(wind_speed_km)
print(f"En vindhastighet pÄ {wind_speed_km} km/t er {wind_speed_ms} m/s.")
---------------------------------------------------------------------------
AssertionError Traceback (most recent call last)
Cell In[4], line 8
4 return speed * 1000 / 3600
7 wind_speed_km = -27
----> 8 wind_speed_ms = convert_kmt_ms(wind_speed_km)
10 print(f"En vindhastighet pÄ {wind_speed_km} km/t er {wind_speed_ms} m/s.")
Cell In[4], line 3, in convert_kmt_ms(speed)
1 def convert_kmt_ms(speed):
2 """Konverterer hastighet fra km/t til m/s"""
----> 3 assert speed >= 0.0, "Vindhastighetsverdier mÄ vÊre positive eller null"
4 return speed * 1000 / 3600
AssertionError: Vindhastighetsverdier mÄ vÊre positive eller null
Fint! NÄ ser vi at nÄr AssertionError
blir flagget, informerer meldingen oss om hvorfor det skjedde uten Ä mÄtte tolke koden. Meldingen gjÞr det ogsÄ enkelt Ä fikse verdien for wind_speed_km
for Ă„ fungere med funksjonen convert_kmt_ms
.
Mer generelt har pÄstander fÞlgende form:
assert <some condition>, "Error message to display"
SĂ„ vi starter med âassertâ-setningen, og gir deretter en logisk test for en tilstand. Hvis testen er sann, skjer ingenting og koden fortsetter. Hvis ikke, stopper koden og en AssertionError
vises med teksten skrevet etter kommaet pÄ linjen som inneholder assert
-setningen.
Flere pÄstander#
Et dÄrlig eksempel#
SelvfĂžlgelig kan det vĂŠre lurt Ă„ ha flere pĂ„stander i en funksjon for Ă„ sikre at den fungerer som forventet og gir meningsfulle verdier. I vĂ„rt tilfelle vil vi kanskje fĂžrst sjekke at verdien som er oppgitt som skal konverteres, er et tall. Hvis ikke, ville vi ikke kunne konvertere enhetene. La oss legge til en ny pĂ„stand for Ă„ sikre at funksjonen vĂ„r er âtryggâ.
def convert_kmt_ms(speed):
"""Konverterer hastighet fra km/t til m/s"""
assert (
type(speed) == int or type(speed) == float
), "Vindhastighetsverdier mÄ vÊre tall"
assert speed >= 0.0, "Vindhastighetsverdier mÄ vÊre positive eller null"
return speed * 1000 / 3600
wind_speed_km = "hund"
wind_speed_ms = convert_kmt_ms(wind_speed_km)
print(f"En vindhastighet pÄ {wind_speed_km} km/t er {wind_speed_ms} m/s.")
---------------------------------------------------------------------------
AssertionError Traceback (most recent call last)
Cell In[5], line 11
7 return speed * 1000 / 3600
10 wind_speed_km = "hund"
---> 11 wind_speed_ms = convert_kmt_ms(wind_speed_km)
13 print(f"En vindhastighet pÄ {wind_speed_km} km/t er {wind_speed_ms} m/s.")
Cell In[5], line 4, in convert_kmt_ms(speed)
1 def convert_kmt_ms(speed):
2 """Konverterer hastighet fra km/t til m/s"""
3 assert (
----> 4 type(speed) == int or type(speed) == float
5 ), "Vindhastighetsverdier mÄ vÊre tall"
6 assert speed >= 0.0, "Vindhastighetsverdier mÄ vÊre positive eller null"
7 return speed * 1000 / 3600
AssertionError: Vindhastighetsverdier mÄ vÊre tall
OK, sĂ„ det fungerer. NĂ„, hvis brukeren prĂžver Ă„ gi en datatype som ikke er âintâ eller âfloatâ, vil funksjonen flagge en âAssertionErrorâ som indikerer at et tall forventes for at funksjonen skal fungere. Dette er greit, men som nevnt nedenfor er det grunner til at du kanskje ikke vil inkludere pĂ„stander av denne typen i en funksjon.
Warning
Man kan forestille seg at det ville vÊre nyttig Ä bruke en pÄstand for Ä sjekke typen til speed
i vÄr funksjon for Ä sikre at man ikke fÄr en TypeError
som oppstod i forrige seksjon. Det viser seg at dette egentlig ikke er en god idé. Grunnen er at den filosofiske ideen bak en TypeError
er Ă„ indikere at du har inkompatible datatyper. Med det i tankene, hvorfor skulle du da utlĂžse en AssertionError
for Ă„ gjĂžre det samme?
Et bedre eksempel#
SÄ vi Þnsker ikke Ä sjekke datatypekompatibiliteten vÄr ved Ä bruke pÄstander, men vi kan inkludere en pÄstand for Ä sikre at maksimum av vindhastigheten er et rimelig tall. I dette tilfellet kan vi anta at vindhastigheten som konverteres ble mÄlt pÄ jorden, og derfor bÞr vÊre lavere enn den raskeste vindhastigheten somnoensinne har blitt mÄlt, 408 km/t. La oss legge til den betingelsen.
def convert_kmt_ms(speed):
"""Konverterer hastighet fra km/t til m/s"""
assert speed >= 0.0, "Vindhastighetsverdier mÄ vÊre positive eller null"
assert speed <= 408.0, "Vindhastigheten er raskere enn noensinne mÄlt tidligere"
return speed * 1000 / 3600
wind_speed_km = "409"
wind_speed_ms = convert_kmt_ms(wind_speed_km)
print(f"En vindhastighet pÄ {wind_speed_km} km/t er {wind_speed_ms} m/s.")
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In[6], line 9
5 return speed * 1000 / 3600
8 wind_speed_km = "409"
----> 9 wind_speed_ms = convert_kmt_ms(wind_speed_km)
11 print(f"En vindhastighet pÄ {wind_speed_km} km/t er {wind_speed_ms} m/s.")
Cell In[6], line 3, in convert_kmt_ms(speed)
1 def convert_kmt_ms(speed):
2 """Konverterer hastighet fra km/t til m/s"""
----> 3 assert speed >= 0.0, "Vindhastighetsverdier mÄ vÊre positive eller null"
4 assert speed <= 408.0, "Vindhastigheten er raskere enn noensinne mÄlt tidligere"
5 return speed * 1000 / 3600
TypeError: '>=' not supported between instances of 'str' and 'float'
Dette er et bedre eksempel av to grunner:
Vi tillater nÄ en
TypeError
nÄr inkompatible datatyper brukes i funksjonen vÄr, som er en klar og kjent feilmelding.Vi bruker pÄstander/assertion for Ä sjekke at verdiene som brukes i funksjonen gir mening for dens tiltenkte bruk. Hvis vi Þnsker Ä hjelpe brukere med Ä konvertere vindhastigheter pÄ jorden, gir vi grenser som sikrer at de bruker rimelige inputverdier. Dermed hjelper vi dem Ä bruke funksjonen vÄr pÄ riktig mÄte.
Kombinert sikrer disse pÄstandene at funksjonen vÄr hÄndterer vanlige feil og gir brukeren nyttig tilbakemelding for Ä kunne bruke funksjonen riktig.
Note
En ting som er viktig Ä merke seg om pÄstander er at selv om vi bruker dem her for Ä sjekke at vÄre inputverdier er rimelige, er dette generelt sett ikke den anbefalte bruken. I stedet anbefaler mer avanserte programmerere Ä bruke pÄstander kun for Ä teste at koden din fungerer riktig internt. For eksempel ville du bruke pÄstander for Ä sjekke ting som ikke skal skje, slik som funksjoner som dupliserer verdier i lister nÄr de ikke skal. Grunnen til at det ikke anbefales Ä bruke pÄstander for Ä teste brukerinputverdier eller eksistensen av filer, er at pÄstander kan deaktiveres ved bruk av flagg nÄr man kjÞrer et Python-program. Dermed er det mulig at de kan bli ignorert helt. Dette er greit nÄr man feilsÞker kode, men Äpenbart ikke Þnskelig nÄr brukere kjÞrer programmene dine. Hvis du er interessert i flere detaljer, kan du gjerne sjekke ut artikkelen om bruk av pÄstander i Python-wikien.
Mer informasjon om pÄstander#
Mer informasjon om pÄstander finner du pÄ Software Carpentry sin nettside.