|
| 1 | +# Classes |
| 2 | + |
| 3 | +Naarmate programma's groter worden neemt de wens voor betere data abstracties toe. Het is makkelijker om na te denken en te praten over concepten in jouw programma zonder het te hebben over de technische details. Zo maakt het niet uit of je een sudoku puzzel representeert met een string, tuple of een list. Wat voor jou en je collega's / medestudenten relevant is is wat je ermee kan. |
| 4 | + |
| 5 | +Object oriented programming geeft jouw het gereedschap om data abstracties te creëeren in jouw programma. Zo kan je data en methodes combineren / bundelen onder één kap. Daarbij krijg je de kans om de interactie te bepalen. Wat kan jouw abstractie en hoe ga je ermee om? |
| 6 | + |
| 7 | +In Python heb je classes, dat zijn beschrijvingen van objecten. Hierin definieer je precies wat een object kan en ook hoe. Zie het als een blauwdruk, waarbij bij elk detail meteen de uitwerking staat. Zie hieronder de class `Coordinate`. |
| 8 | + |
| 9 | + |
| 10 | + class Coordinate: |
| 11 | + def __init__(self, x, y): |
| 12 | + self.x = x |
| 13 | + self.y = y |
| 14 | + |
| 15 | + def distance_to(self, other): |
| 16 | + return (abs(self.x - other.x)**2 + abs(self.y - other.y)**2)** 0.5 |
| 17 | + |
| 18 | + |
| 19 | +Bovenstaande class introduceert een nieuw type in ons programma namelijk `Coordinate`. Vanaf nu kan je instanties ofwel objecten van het type `Coordinate` maken. Dit doe je als volgt: |
| 20 | + |
| 21 | + |
| 22 | + coord1 = Coordinate(3, 5) |
| 23 | + coord2 = Coordinate(2, 8) |
| 24 | + |
| 25 | + |
| 26 | +Hier gebeurt het volgende, zodra je de class `Coordinate` aanroept, roept Python de methode `__init__` voor je aan. Init is kort voor initialize, ofwel de methode die wordt aangeroepen bij het initialiseren van een object. De methode `__init__` accepteert hier 3 argumenten. Dit is waar Python een beetje hacky wordt, want het eerst argument `self` vult Python voor je in. Dat is een referentie/verwijzing naar het object. Dat dit argument `self` heet is conventie, we doen het allemaal, maar het hoeft niet. Naast `self` staan nog 2 argumenten, hier `x` en `y`. Logisch ook want we hebben het over een coordinaat! Omdat er 2 argumenten naast `self` zijn moet je deze bij het aanmaken van een `Coordinate` ook meegeven, zo wordt er voor `coord1` de waarde `3` meegegeven voor `x` en `5` voor `y`. Op de regels daarna wordt er nieuwe zogenaamde "instance variables" aangemaakt voor het `Coordinate`, `.x` en `.y` respectievelijk. Daaraan worden de waardes `3` en `5` bij `coord1` toegekend. |
| 27 | + |
| 28 | +## Instance variables |
| 29 | + |
| 30 | +Een instance variable is een variabele die enkel beschikbaar is voor die instantie. Zo hebben `coord1` en `coord2` allebei een instance variable genaamd `.x`, maar deze heeft een hele andere waarde. Test het volgende maar eens: |
| 31 | + |
| 32 | + |
| 33 | + print(coord1.x) |
| 34 | + print(coord2.x) |
| 35 | + |
| 36 | + |
| 37 | +Dat is ook hoe je bij de waardes van de `instance variable`s komt. Namelijk het object (de instance) en vervolgens een `.` en daarna de variabele naam. |
| 38 | + |
| 39 | +Dit is super handig, want nu kunnen we een naam toekennen aan deze variabelen. Zo hoef je het niet meer te hebben over plek 0 en 1, maar kan je nadenken over een x en y coordinaat. Neemt weer wat cognitive load af en zo kan je collega niet de fout maken om `x` en `y` door elkaar te halen! |
| 40 | + |
| 41 | +## Methods |
| 42 | + |
| 43 | +Naast variabelen kunnen we ook functies toe kennen aan een class. Deze noemen we dan net even anders: `methods`. Dat zijn simpelweg functies behorende bij een class. Beide namen worden vaak door elkaar gebruikt! |
| 44 | + |
| 45 | +Hiermee kunnen we niet alleen data groeperen onder één kap, maar ook de bijbehorende operaties en code. De class `Coordinate` kent dan ook één method genaamd `distance_to`. Elke method accepteert in Python altijd als eerst een verwijzing naar het object, die ene instantie waarvan de afstand willen weten, weer per conventie `self` genoemd. Daarnaast kan een method 0 of meer argumenten accepteren. `distance_to` accepteert er één meer, namelijk `other`. Klinkt logisch, we hebben het coordinaat `self` en een `other`. |
| 46 | + |
| 47 | +Wat de method `distance_to` vervolgens doet is de afstand tussen de twee coordinaten berekenen. Daarom ook de naam `distance_to`! Je kan de method als volgt gebruiken: |
| 48 | + |
| 49 | + |
| 50 | + coord1.distance_to(coord2) |
| 51 | + |
| 52 | + |
| 53 | +Voor Python is dit equivalent aan: |
| 54 | + |
| 55 | + |
| 56 | + Coordinate.distance_to(coord1, coord2) |
| 57 | + |
| 58 | + |
| 59 | +Het eerste is enkel minder typen! |
| 60 | + |
| 61 | +## Class variables |
| 62 | + |
| 63 | +Daarnaast bestaan er class variables. Deze verschillen niet per object/instantie van een class, maar bestaan één keer voor alle objecten van een class. |
| 64 | + |
| 65 | + |
| 66 | + class Request: |
| 67 | + count = 0 |
| 68 | + |
| 69 | + def __init__(self, type, message): |
| 70 | + # do something with type and message |
| 71 | + Request.count += 1 |
| 72 | + |
| 73 | +Zo heeft de class `Request` hierboven een class variable `count`. Deze wordt elke keer opgehoogd bij het initialiseren van een instantie van Request. |
| 74 | + |
| 75 | + |
| 76 | + print(Request.count) # prints 0 |
| 77 | + request1 = Request("get", "homepage") |
| 78 | + print(Request.count) # prints 1 |
| 79 | + print(request1.count) # prints 1 |
| 80 | + request2 = Request("get", "accountpage") |
| 81 | + print(Request.count) # prints 2 |
| 82 | + print(request1.count) # prints 2 |
| 83 | + print(request2.count) # prints 2 |
| 84 | + |
| 85 | + |
| 86 | +Je kan via de class `Request` zelf bij de class variabele, maar ook via elke instantie/object van de class, in het voorbeeld hierboven `request1` en `request2`. Het zijn verschillende wegen naar Rome, maar de uitkomst is hetzelfde, de waarde van de class variabele `count`! |
| 87 | + |
| 88 | + |
| 89 | +## Hidden methods |
| 90 | + |
| 91 | +Python is gebouwd op Object Oriented Programming. Bijna alle constructies in de taal vertalen naar een method call. Bijvoorbeeld: |
| 92 | + |
| 93 | + |
| 94 | + a = 1 |
| 95 | + b = 3 |
| 96 | + a = a + b |
| 97 | + print(a) |
| 98 | + |
| 99 | + |
| 100 | +Is eigenlijk het volgende: |
| 101 | + |
| 102 | + |
| 103 | + a = 1 |
| 104 | + b = 3 |
| 105 | + a = a.__add__(b) |
| 106 | + print(a.__str__()) |
| 107 | + |
| 108 | + |
| 109 | +Wat Python hiermee bereikt is dat jij als programmeur zelf kan bepalen wat er moet gebeuren als je bijvoorbeeld twee `Coordinate`s bij elkaar optelt, of hoe een `Coordinate` eruit moet zien als jij deze uitprint. Je moet alleen even opzoeken wat je precies moet implementeren en vervolgens rest de taak om het te implemteren. Bijvoorbeeld als volgt: |
| 110 | + |
| 111 | + |
| 112 | + class Coordinate: |
| 113 | + def __init__(self, x, y): |
| 114 | + self.x = x |
| 115 | + self.y = y |
| 116 | + |
| 117 | + def __str__(self): |
| 118 | + return f"coord: {x},{y}" |
| 119 | + |
| 120 | + def __add__(self, other): |
| 121 | + return Coordinate(self.x + other.x, self.y + other.y) |
| 122 | + |
| 123 | + def distance_to(self, other): |
| 124 | + return (abs(self.x - other.x)**2 + abs(self.y - other.y)**2)** 0.5 |
| 125 | + |
| 126 | +Met zowel de `__str__` en `__add__` methodes geïmplementeerd kunnen we vervolgens het `+` teken en de functie `print()` gebruiken voor instanties/objecten van `Coordinate`. |
| 127 | + |
| 128 | + |
| 129 | + coord1 = Coordinate(3, 5) |
| 130 | + coord2 = Coordinate(2, 8) |
| 131 | + print(coord1) # print coord: 3,5 |
| 132 | + print(coord2) # print coord 2,8 |
| 133 | + print(coord1 + coord2) # print coord 5,13 |
0 commit comments