Fijne functies

Deze pagina bevat uitvoerbare code.

Opdracht: Fijne functies

Opdracht 1: sq(x)

def sq(x):
    """Geeft het kwadraat van x terug"""
    return x * x


assert sq(5) == 25
assert sq(-3) == 9
assert sq(0) == 0

Het kwadraat is het getal maal zichzelf, dus de berekening past in de returnregel. De derde assertion dekt het randgeval nul, waar de vermenigvuldiging niets meer oplevert dan nul.

Opdracht 2: interp(low, hi, fraction)

def interp(low, hi, fraction):
    """Geeft de waarde op fractie fraction tussen low en hi terug"""
    return low + (hi - low) * fraction


assert interp(1.0, 9.0, 0.25) == 3.0
assert interp(1.0, 3.0, 0.25) == 1.5
assert interp(24, 42, 0) == 24
assert interp(102, 117, -4.0) == 42.0

(hi - low) is de afstand tussen de twee waarden. Daar een deel van nemen en bij low optellen geeft het antwoord, zonder ook maar één if.

De derde assertion is het randgeval: bij fractie 0 blijf je op low staan. Let op dat er dan 24 uitkomt en niet 24.0 - er is geen enkel floating-point getal bij de berekening betrokken. De vierde laat zien dat een fractie buiten het bereik 0 tot 1 gewoon werkt.

Opdracht 3: checkends(s)

def checkends(s):
    """Geeft True als het eerste en het laatste karakter van s gelijk zijn"""
    return s[0] == s[-1]


assert checkends("niet gelijk") is False
assert checkends("kijk! wel gelijk") is True
assert checkends("q") is True
assert checkends(" ") is True

Een vergelijking met == levert zelf al True of False op, dus een if-else eromheen voegt niets toe.

Bij een string van één karakter wijzen s[0] en s[-1] naar hetzelfde karakter, en dat is dus altijd True. Dat is het randgeval, en de string met één spatie werkt om dezelfde reden.

Opdracht 4: swap_ends(s)

def swap_ends(s):
    """Geeft s terug met het eerste en het laatste karakter verwisseld"""
    if len(s) < 2:
        return s

    return s[-1] + s[1:-1] + s[0]


assert swap_ends("hond") == "donh"
assert swap_ends("python") == "nythop"
assert swap_ends("ab") == "ba"
assert swap_ends("q") == "q"
assert swap_ends("") == ""

De middenstukken haal je met een slice op: s[1:-1] is alles behalve het eerste en het laatste karakter.

Zonder de controle op de lengte gaat het mis bij een string van één karakter: s[0] en s[-1] wijzen dan naar hetzelfde karakter, en swap_ends("q") zou "qq" teruggeven. Precies daarom staat dat geval erbij als assertion.

Opdracht 5: convert_from_seconds(seconds)

def convert_from_seconds(seconds):
    """Zet een aantal seconden om naar [dagen, uren, minuten, seconden]"""
    days = seconds // (24 * 60 * 60)
    seconds = seconds % (24 * 60 * 60)

    hours = seconds // (60 * 60)
    seconds = seconds % (60 * 60)

    minutes = seconds // 60
    seconds = seconds % 60

    return [days, hours, minutes, seconds]


assert convert_from_seconds(610) == [0, 0, 10, 10]
assert convert_from_seconds(100000) == [1, 3, 46, 40]
assert convert_from_seconds(0) == [0, 0, 0, 0]
assert convert_from_seconds(59) == [0, 0, 0, 59]

Elke stap doet twee dingen: met // de grootste eenheid eruit halen, en met % het restant bewaren voor de volgende stap. Daardoor staat de berekening drie keer in dezelfde vorm en hoef je nergens uit te rekenen wat er al af is.

24 * 60 * 60 blijft staan zoals het is en wordt geen 86400: zo lees je aan de regel zelf af dat het om een dag gaat.

Nul seconden is het randgeval; alle vier de waarden zijn dan nul.