Python-Py7h0n programmeertaal leuke weetjes

In Python (een programmeertaal) kun je soms tegen rare dingen aan lopen, soms verwacht je niet altijd wat je krijgt (hoewel het achteraf altijd wel uit te leggen is). Dit geld overigens voor alle programmeertalen op de wereld. 😉

Voorbeeld #1

Hieronder een leuk voorbeeld:

>>> 2 == 2
True
>>> 2 == 3
False
>>> 100.0 == 100.000000
True
>>> 100 == 100.000000000001
False
>>> 100.0 == 100.0000000001
False
>>> 100.0 == 100.00000000000000001

Wat verwacht je bij de laatste? Een False (niet waar)? Helaas het is True (waar).  De repr() functie zorgt voor een printbare representatie van het object die voor de afronding zorgt. Als je de print of str() functie zou gebruiken krijg je ook een printbare representatie, maar leesbaar voor de mens.

Ps.
Daarnaast wordt de waarde omgezet wordt naar een float type object (een type getal), echter dit type heeft een limiet aan hoeveel significante cijfers het kan bevatten. 17 om precies te zijn.

Zie voorbeeld hieronder:

>>> 100.0000000000001  # roept repr() functie onderwater aan  
100.00000000000001
>>> 100.000000000000001 # roept repr() functie onderwater aan
100.0
>>> print 100.000000001 # roept str() functie onderwater aan
100.000000001
>>> print 100.0000000001 # roept str() functie onderwater aan
100.0

Voorbeeld #2

>>> data = dict()
>>> data["sub"] = dict()
>>> data["sub"]["x"] = 2
>>> data
{'sub': {'x': 2}}
>>> local_data = data
>>> path = ["sub", "x"]
>>> for attribute in path:
...     local_data = local_data[attribute]
...     if type(local_data) != dict:
...             print "current value:", local_data
...             local_data = 3
... 
current value: 2
>>> local_data
3

Op zich logisch wat er nu gebeurd. Je verwijst uiteindelijk een getal toe aan een variabele (het getal 3), dit komt omdat het laatste object in deze dictonary een getal is. En een getal in Python is imutable (im wattes?). Ik kom daar later op terug…  Maar wat nu als je de gehele structuur wilt behouden en daarin een wijziging wilt brengen? Kortom je verwacht eigenlijk het volgende:

>>> local_data
{'sub': {'x': 3}}

Theorie

Je hebt programmeer talen die werken met “by value” of “by reference”, zoals in C++ kun je via referentie werken (ook wel pointers genoemd). Maar is Python nu ‘by value’ of ‘by reference’? Correcte antwoord op deze vraag: geen van beide :). Eigenlijk is “aanroep-via-object”, of “aanroep-via-object-referentie” een betere manier van beschrijven. Maar wat betekend “aanroep-via-object” nu eigenlijk?

In Python is (bijna) alles een object. Wat we normaal gesproken naar verwijzen als variabele in Python, wordt in Python meer waarschijnlijk aangeduid als ‘names’. Bovendien, het “toewijzen” binnen Python is eigenlijk niks anders dan een naam verbinden aan een object.

Nu komt het leukste verhaal. Een dictionary en lists zijn mutable, dit betekend dat het gewijzigd kan worden. Echter een nummer (zoals hierboven, nummer 2), strings en tuples zijn immutable. Als je immutable object wijzigt binnen een functie/methode, dat creëert Python een nieuwe instantie en de originele instant buiten de functie/methode is dan niet veranderd. Echter een dictionary was dus mutable, dat betekent dat kan wijzigen op de plek waar jij het wilt. Daarom zou een mutable object binnen een functie/methode ook het object buiten deze functie/methode veranderen.

Praktijk

Nu we de theorie weten, kunnen we dit toepassen. Mogelijke oplossing voor dit probleem zou dan kunnen zijn:

def dpath_set(d, path, val):
path = path.split('.')
path, last = path[:-1], path[-1]
for x in path:
d = d[x]
d[last] = val
>>> local_data
{'sub': {'x': 2}}
>>> dpath_set(local_data, 'sub.x',3)
>>> local_data
{'sub': {'x': 3}}

Succes met coden!

Did you like the article? Please share!