Types

Introductie

Type hints in Python zijn een krachtige manier om de leesbaarheid en betrouwbaarheid van je code te verbeteren. Hoewel Python een dynamisch getypeerde taal is, kun je met type hints duidelijk maken welk type gegevens een functie verwacht of retourneert. In dit hoofdstuk beginnen we met een overzicht van vaak gebruikte types en eindigen we met een voorbeeld van een eenvoudige class waarin type hints consistent worden toegepast.

Hieronder volgt een overzicht van de meest voorkomende types die je in Python kunt gebruiken met type hints. Deze types worden gedefinieerd in het standaard “typing”-module of zijn ingebouwde types in Python.

Basistypes

  • int: Voor gehele getallen, bijvoorbeeld 42 of -3.
  • float: Voor kommagetallen, bijvoorbeeld 3.14 of -0.001.
  • str: Voor tekst, bijvoorbeeld 'Hallo' of "Python".
  • bool: Voor waarheidswaarden, bijvoorbeeld True of False.

Complexere types

  • list: Voor lijsten, bijvoorbeeld [1, 2, 3] of ['a', 'b', 'c']. Gebruik List[<type>] uit de typing-module om het type van de lijst te specificeren, zoals List[int].
  • tuple: Voor tupels, bijvoorbeeld (1, 2) of ('x', 'y'). Gebruik Tuple[<type1>, <type2>].
  • dict: Voor woordenboeken, bijvoorbeeld {'key': 'value'} of {1: 'a'}. Specificeer met Dict[<key_type>, <value_type>], zoals Dict[str, int].
  • set: Voor verzamelingen, bijvoorbeeld {1, 2, 3}. Specificeer met Set[<type>], zoals Set[str].

Speciale types

  • Optional: Wanneer een variabele None kan zijn of een waarde van een ander type, bijvoorbeeld Optional[int].
  • Union: Voor variabelen die meerdere types kunnen hebben, bijvoorbeeld Union[int, str].
  • Any: Wanneer je elk type wilt toestaan.
  • Callable: Voor functies, bijvoorbeeld Callable[[int, int], int] voor een functie die twee integers accepteert en een integer retourneert.

Voorbeeld

Hier is een korte functie met type hints:

def optel_sommen(getallen: List[int]) -> int:
    totaal = sum(getallen)
    return totaal

In dit voorbeeld geeft List[int] aan dat de parameter getallen een lijst van gehele getallen moet zijn, en -> int geeft aan dat de functie een geheel getal retourneert.


Type hints in een class

Hier is een voorbeeld van een eenvoudige class waarin type hints consistent worden gebruikt:

from typing import List

class Student:
    def __init__(self, naam: str, leeftijd: int, cijfers: List[float]):
        self.naam: str = naam
        self.leeftijd: int = leeftijd
        self.cijfers: List[float] = cijfers

    def gemiddelde(self) -> float:
        return sum(self.cijfers) / len(self.cijfers)

    def voeg_cijfer_toe(self, cijfer: float) -> None:
        self.cijfers.append(cijfer)

# Gebruik van de class
student = Student(naam="Jan", leeftijd=17, cijfers=[8.5, 7.0, 9.0])
print(f"Gemiddelde: {student.gemiddelde()}")
student.voeg_cijfer_toe(8.0)
print(f"Nieuwe cijfers: {student.cijfers}")

Wat gebeurt hier?

  1. Constructor: De constructor (__init__) gebruikt type hints om aan te geven dat naam een string is, leeftijd een integer, en cijfers een lijst van floats.
  2. Methodes: De methode gemiddelde geeft een float terug, en voeg_cijfer_toe retourneert niets (None).
  3. Gebruik: Het voorbeeld toont hoe je een instantie van de class maakt en hoe de methodes worden gebruikt.

Waarom type hints gebruiken?

  • Leesbaarheid: Anderen (of jijzelf!) begrijpen sneller wat de code doet.
  • Foutopsporing: Tools zoals linters of IDE’s kunnen je waarschuwen voor typefouten.
  • Documentatie: Je code fungeert als zelfdocumenterende documentatie.

Oefening

Hier is een class zonder type hints. Voeg type hints toe aan de constructor en methodes zodat duidelijk wordt welke types de class gebruikt.

class Boek:
    def __init__(self, titel, auteur, paginas):
        self.titel = titel
        self.auteur = auteur
        self.paginas = paginas

    def samenvatting(self):
        return f"{self.titel} is geschreven door {self.auteur}."

    def is_dik_boek(self):
        return self.paginas > 300

# Gebruik van de class
boek = Boek("Python Programmeren", "Jan Jansen", 350)
print(boek.samenvatting())
print(f"Is het een dik boek? {boek.is_dik_boek()}")

Type hints en onverwachte types

Hoewel type hints aangeven welk type verwacht wordt, zijn ze geen harde beperking. Hier is een voorbeeld:

Basisvoorbeeld met isinstance

def kwadraat_getal(getal: int) -> int:
    if not isinstance(getal, int):
        print("Onverwacht type!")
    return getal ** 2

# Gebruik van de functie met een verkeerd type
resultaat = kwadraat_getal("4")  # Geen foutmelding, maar onverwacht gedrag
print(resultaat)

In het bovenstaande voorbeeld wordt een string doorgegeven aan een functie die een integer verwacht. Python geeft geen foutmelding, maar het gedrag is onverwacht.

Introductie van raise

Het keyword raise wordt gebruikt om een foutmelding expliciet te genereren. Hiermee kun je typecontroles uitvoeren in je code.

def kwadraat_getal(getal: int) -> int:
    if not isinstance(getal, int):
        raise TypeError("De waarde moet een integer zijn!")
    return getal ** 2

# Correct gebruik
print(kwadraat_getal(4))  # Geeft 16

# Onjuist gebruik
print(kwadraat_getal("4"))  # Geeft een TypeError

Controle met lijsten

Hier is een voorbeeld met een lijst:

def optel_sommen(getallen: List[int]) -> int:
    if not all(isinstance(x, int) for x in getallen):
        raise TypeError("Alle elementen in de lijst moeten integers zijn.")
    return sum(getallen)

# Correct gebruik
print(optel_sommen([1, 2, 3]))  # Geeft 6

# Onjuist gebruik
print(optel_sommen([1, 2, "3"]))  # Geeft een TypeError

Oefeningen

  1. Controleer een string: Schrijf een functie controleer_tekst(tekst: str) -> str die controleert of de invoer een string is. Geef een foutmelding als dat niet zo is.

  2. Controleer een float: Schrijf een functie bereken_kwadraat(getal: float) -> float die controleert of de invoer een float is en het kwadraat retourneert. Geef een foutmelding als dat niet zo is.

  3. Controleer een lijst van strings: Schrijf een functie combineer_woorden(woorden: List[str]) -> str die controleert of alle elementen in de lijst strings zijn en ze vervolgens combineert tot één string. Geef een foutmelding als dat niet zo is.

Vereenvoudiging met Typeguard

Met de bibliotheek typeguard kun je typecontroles automatiseren zonder dat je handmatig isinstance of raise hoeft te gebruiken. Typeguard valideert automatisch de types van de parameters en retourwaarden van functies.

Installatie

Je kunt typeguard installeren met pip:

pip install typeguard

Gebruik van Typeguard

Hier is een voorbeeld van hoe je typeguard kunt gebruiken:

from typeguard import typechecked

@typechecked
def kwadraat_getal(getal: int) -> int:
    return getal ** 2

# Correct gebruik
print(kwadraat_getal(4))  # Geeft 16

# Onjuist gebruik
print(kwadraat_getal("4"))  # Geeft een TypeError

In dit voorbeeld controleert typeguard automatisch of de parameter getal een integer is en of de retourwaarde overeenkomt met de opgegeven type hint.

Controle met lijsten

Je kunt typeguard ook gebruiken met complexere types, zoals lijsten:

from typing import List
from typeguard import typechecked

@typechecked
def optel_sommen(getallen: List[int]) -> int:
    return sum(getallen)

# Correct gebruik
print(optel_sommen([1, 2, 3]))  # Geeft 6

# Onjuist gebruik
print(optel_sommen([1, 2, "3"]))  # Geeft een TypeError

Voordelen van Typeguard

  • Automatisch: Je hoeft geen handmatige controles met isinstance of raise te schrijven.
  • Consistent: Typeguard werkt direct samen met de type hints die je al hebt gedefinieerd.
  • Efficiënt: Het maakt je code overzichtelijker en onderhoudsvriendelijker.

Oefeningen

  1. Eenvoudige functie: Schrijf een functie vermenigvuldig_getallen(a: int, b: int) -> int die de twee parameters vermenigvuldigt. Gebruik typeguard om de types te controleren.

  2. Lijstfunctie: Schrijf een functie bereken_gemiddelde(cijfers: List[float]) -> float die het gemiddelde van een lijst berekent. Gebruik typeguard om te controleren of alle invoer correct is.

  3. Complexere functie: Schrijf een functie beschrijf_boek(titel: str, paginas: int, auteurs: List[str]) -> str die een string retourneert met een beschrijving van een boek. Gebruik typeguard om de types van de parameters te valideren.


Typefouten detecteren met Pylance

Pylance is een krachtige extensie voor Visual Studio Code die je helpt typefouten in je Python-code al tijdens het typen te detecteren, zonder dat je de code hoeft uit te voeren. Het integreert met type hints en laat je meteen zien of er problemen zijn met de types in je code.

Installatie van Pylance

  1. Open Visual Studio Code.
  2. Ga naar de extensies-marktplaats (Ctrl+Shift+X of Cmd+Shift+X op Mac).
  3. Zoek naar “Pylance”.
  4. Klik op “Install” om de extensie te installeren.
  5. Zorg ervoor dat je ook de Python-extensie van Microsoft hebt geïnstalleerd.
  6. Open File -> Preferences -> Settings en zoek naar type checking mode. Stel in op Standard.

Gebruik van Pylance

Zodra Pylance is geïnstalleerd:

  1. Zorg ervoor dat je type hints toevoegt aan je code.
  2. Open een Python-bestand in Visual Studio Code.
  3. Typ of plak code met type hints. Pylance analyseert de code direct en onderstreept eventuele typefouten.

Bonus: Comments

Met type hints krijg je nu meer feedback in VS Code. Je nu, wanneer je met je muis over een functie beweegt, zien welke argumenten de functie verwacht. Zou het nu niet handig zijn als je ook uitleg krijgt over de functie? Dat kan!

Om in Python comments bij een functie te schrijven die Visual Studio Code (en andere editors) weergeeft als hints bij het gebruik van de functie, gebruik je docstrings en type hints. Een docstring is een string die direct onder de definitie van de functie wordt geplaatst en de functionaliteit van de functie beschrijft.

Hier is hoe je dat doet:

Stappen

  1. Gebruik docstrings:
    • Schrijf een beschrijvende tekst tussen drie aanhalingstekens (""" of ''') direct na de functiedefinitie.
    • Beschrijf wat de functie doet, wat de parameters zijn en wat de functie retourneert.
  2. Gebruik type hints:
    • Voeg type-informatie toe aan de parameters en de returnwaarde om duidelijk te maken welke types verwacht worden.

Hier is een voorbeeld:

def greet(name: str, age: int) -> str:
    """
    Geeft een gepersonaliseerde begroeting terug.

    Parameters:
    name (str): De naam van de persoon.
    age (int): De leeftijd van de persoon.

    Returns:
    str: Een gepersonaliseerde begroetingsstring.
    """
    return f"Hallo {name}, je bent {age} jaar oud!"

Waarom werkt dit?

  1. Docstring:
    • Wanneer je in Visual Studio Code met je muis over de functie zweeft, wordt de inhoud van de docstring weergegeven.
    • De docstring wordt ook weergegeven in de IntelliSense van VS Code (de automatische aanvulfunctie).
  2. Type hints:
    • VS Code gebruikt de type hints om aan te geven welke types verwacht worden voor parameters en de returnwaarde. Dit maakt het gebruik van de functie duidelijker en helpt bij foutopsporing.

Gebruik in VS Code

Wanneer je deze functie aanroept, zie je iets zoals dit in Visual Studio Code:

greet("Alice", 25)

Als je de muis over greet beweegt of de parameters invult, toont VS Code:

  • De docstring: een korte uitleg van de functie en de parameters.
  • De type hints: wat voor waarden de functie verwacht en retourneert.

Dit maakt je code veel leesbaarder en gebruiksvriendelijker, zowel voor jezelf als voor anderen die je code gebruiken!


Previous section:
Navigatie