← Terug naar overzicht
Basisconcepten · Python

Data types

Basistypen, collection types, type conversion, en een verdieping over floats en bits

Python is dynamically typed: je hoeft het type van een variabele niet expliciet op te geven, Python leidt dit af op basis van de waarde.

1.1 De basistypen

geheel_getal = 42          # int
kommagetal = 3.14          # float
tekst = "Hallo wereld"     # str
waarheid = True            # bool
niets = None                # NoneType

Je kunt het type van een variabele controleren met type():

print(type(geheel_getal))  # <class 'int'>
print(type(kommagetal))    # <class 'float'>

1.2 Collection types

TypeMutable?Ordered?Voorbeeld
listJaJa[1, 2, 3]
tupleNeeJa(1, 2, 3)
dictJaJa (sinds 3.7){"naam": "Ernest"}
setJaNee{1, 2, 3}
mijn_lijst = [1, 2, 3]
mijn_tuple = (1, 2, 3)
mijn_dict = {"naam": "Rachel", "huisdieren": 2}
mijn_set = {1, 2, 2, 3}   # dubbele waarden verdwijnen automatisch

print(mijn_set)   # {1, 2, 3}

1.3 Type conversion

Je kunt waarden expliciet omzetten naar een ander type met int(), float() en str().

x = "10"                # str
y = int(x)               # 10, nu een int
z = float(x)              # 10.0, nu een float

print(type(x), x)   # <class 'str'> 10
print(type(y), y)   # <class 'int'> 10
print(type(z), z)   # <class 'float'> 10.0

Conversie naar een string gaat net zo, met str(). Dit is bijvoorbeeld nodig als je een getal wilt samenvoegen met tekst, want + werkt niet zomaar tussen een str en een int:

aantal_huisdieren = 3

# print("Ik heb " + aantal_huisdieren + " huisdieren")   # FOUT! kan str en int niet optellen
print("Ik heb " + str(aantal_huisdieren) + " huisdieren")  # werkt wel

print(type(str(aantal_huisdieren)))   # <class 'str'>

1.4 Verdieping: floats en bits

Een float gedraagt zich soms verrassend, bijvoorbeeld: 0.1 + 0.2 != 0.3. Om te begrijpen waarom, is het nuttig om te weten wat een float eigenlijk is op bit-niveau.

IEEE 754 (double precision, 64-bit)

Python's standaard float is een 64-bit getal volgens de IEEE 754-standaard ("double precision"). Deze 64 bits zijn verdeeld in drie delen:

OnderdeelAantal bitsFunctie
Sign1 bit0 = positief, 1 = negatief
Exponent11 bitsbepaalt de "schaal" (macht van 2)
Mantissa (fraction)52 bitsde significante cijfers

De bits daadwerkelijk bekijken

Met de module struct kun je een float omzetten naar zijn ruwe bits:

import struct

def toon_bits(getal):
    # pak de float in 8 bytes, volgens IEEE 754
    data = struct.pack('>d', getal)
    # zet elke byte om naar 8 bits (0'en en 1'en)
    bits = ''.join(format(byte, '08b') for byte in data)
    return bits

bits = toon_bits(1.0)
print("Alle 64 bits: ", bits)
print("Sign (1 bit):      ", bits[0])
print("Exponent (11 bit): ", bits[1:12])
print("Mantissa (52 bit): ", bits[12:])

Vergelijk de uitkomst voor een paar verschillende getallen:

print(toon_bits(1.0))
print(toon_bits(-1.0))    # alleen het sign-bit verandert
print(toon_bits(2.0))     # exponent verandert, mantissa blijft gelijk
print(toon_bits(0.1))     # geen "nette" bitpatroon -> kern van het probleem

Waarom 0.1 + 0.2 niet precies 0.3 is

Een float heeft een eindig aantal bits, dus een eindige precisie. Niet elk decimaal getal past exact in dat bitpatroon, net zoals 1/3 geen eindig aantal decimalen heeft in het tientallig stelsel. 0.1 is in binaire vorm een oneindig repeterende reeks, en wordt daarom afgerond opgeslagen in de beschikbare bits. Dat verklaart dit klassieke voorbeeld:

print(0.1 + 0.2)          # 0.30000000000000004
print(0.1 + 0.2 == 0.3)   # False

Vuistregel: vergelijk floats nooit met ==. Gebruik round() of een kleine tolerantie:

print(round(0.1 + 0.2, 2) == 0.3)   # True