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.
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'>
| Type | Mutable? | Ordered? | Voorbeeld |
|---|---|---|---|
list | Ja | Ja | [1, 2, 3] |
tuple | Nee | Ja | (1, 2, 3) |
dict | Ja | Ja (sinds 3.7) | {"naam": "Ernest"} |
set | Ja | Nee | {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}
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'>
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.
Python's standaard float is een 64-bit getal volgens de IEEE 754-standaard ("double precision"). Deze 64 bits zijn verdeeld in drie delen:
| Onderdeel | Aantal bits | Functie |
|---|---|---|
| Sign | 1 bit | 0 = positief, 1 = negatief |
| Exponent | 11 bits | bepaalt de "schaal" (macht van 2) |
| Mantissa (fraction) | 52 bits | de significante cijfers |
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
0.1 + 0.2 niet precies 0.3 isEen 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
==. Gebruikround()of een kleine tolerantie:print(round(0.1 + 0.2, 2) == 0.3) # True