Python – Objectgeoriënteerd

Advertenties

Python is al een objectgeoriënteerde taal sinds het bestaan ervan. Hierdoor is het maken en gebruiken van klassen en objecten ronduit eenvoudig. Dit hoofdstuk helpt je om een expert te worden in het gebruik van Python’s object-georiënteerde programmeerondersteuning.

Als je geen eerdere ervaring hebt met object-georiënteerd (OO) programmeren, kun je misschien beter een inleidende cursus raadplegen of op zijn minst een of andere tutorial, zodat je de basisbegrippen begrijpt.

Hoe dan ook, hier volgt een kleine introductie van Object-georiënteerd programmeren (OOP) om je op snelheid te brengen –

Overzicht van OOP-terminologie

  • Klasse – Een door de gebruiker gedefinieerd prototype voor een object dat een reeks attributen definieert die elk object van de klasse kenmerken. De attributen zijn gegevensleden (klassevariabelen en instance-variabelen) en methoden, die toegankelijk zijn via puntnotatie.

  • Klassevariabele – Een variabele die wordt gedeeld door alle instanties van een klasse. Klassevariabelen worden gedefinieerd binnen een klasse maar buiten de methoden van de klasse. Klassevariabelen worden niet zo vaak gebruikt als instance-variabelen.

  • Gegevenslid – Een klassevariabele of instance-variabele die gegevens bevat die zijn geassocieerd met een klasse en haar objecten.

  • Functie-overloading – De toewijzing van meer dan één gedrag aan een bepaalde functie. De uitgevoerde bewerking varieert naargelang van de betrokken soorten objecten of argumenten.

  • Instantievariabele – Een variabele die binnen een methode wordt gedefinieerd en alleen behoort tot de huidige instantie van een klasse.

  • Erfenis – De overdracht van de kenmerken van een klasse naar andere klassen die ervan zijn afgeleid.

  • Instantie – Een individueel object van een bepaalde klasse. Een object obj dat bijvoorbeeld behoort tot een klasse Cirkel, is een instantie van de klasse Cirkel.

  • Instantiatie – Het creëren van een instantie van een klasse.

  • Methode – Een speciaal soort functie die wordt gedefinieerd in een klassedefinitie.

  • Object – Een unieke instantie van een gegevensstructuur die wordt gedefinieerd door de klasse. Een object omvat zowel gegevensleden (klassevariabelen en instance-variabelen) als methoden.

  • Operator overloading – De toewijzing van meer dan één functie aan een bepaalde operator.

Klassen maken

Met de klasse-instructie wordt een nieuwe klasse-definitie gemaakt. De naam van de klasse volgt onmiddellijk op het trefwoord klasse gevolgd door een dubbele punt, als volgt –

class ClassName: 'Optional class documentation string' class_suite

  • De klasse heeft een documentatiestring, die kan worden geopend via ClassName.__doc__.

  • De klasse_suite bestaat uit alle component-statements waarin de leden, gegevensattributen en functies van de klasse worden gedefinieerd.

Voorbeeld

Hieronder volgt een voorbeeld van een eenvoudige Python-klasse –

class Employee: 'Common base class for all employees' empCount = 0 def __init__(self, name, salary): self.name = name self.salary = salary Employee.empCount += 1 def displayCount(self): print "Total Employee %d" % Employee.empCount def displayEmployee(self): print "Name : ", self.name, ", Salary: ", self.salary
  • De variabele empCount is een klassevariabele waarvan de waarde wordt gedeeld door alle instanties van een deze klasse. Deze kan worden benaderd als Employee.empCount van binnen de klasse of buiten de klasse.

  • De eerste methode __init__() is een speciale methode, die klasseconstructor of initialisatiemethode wordt genoemd en die Python aanroept wanneer je een nieuwe instantie van deze klasse maakt.

  • De andere methoden van de klasse declareer je zoals normale functies, met de uitzondering dat het eerste argument van elke methode self is. Python voegt het self-argument voor u toe aan de lijst; u hoeft het niet op te nemen wanneer u de methoden aanroept.

Creëren van instantie-objecten

Om instanties van een klasse te creëren, roept u de klasse aan met de klassenaam en geeft u de argumenten op die de __init__-methode accepteert.

"This would create first object of Employee class"emp1 = Employee("Zara", 2000)"This would create second object of Employee class"emp2 = Employee("Manni", 5000)

Toegang tot attributen

U krijgt toegang tot de attributen van het object met behulp van de punt-operator met object. Klassenvariabelen worden als volgt benaderd met de klassenaam –

emp1.displayEmployee()emp2.displayEmployee()print "Total Employee %d" % Employee.empCount

Nu alle concepten samengevoegd –

#!/usr/bin/pythonclass Employee: 'Common base class for all employees' empCount = 0 def __init__(self, name, salary): self.name = name self.salary = salary Employee.empCount += 1 def displayCount(self): print "Total Employee %d" % Employee.empCount def displayEmployee(self): print "Name : ", self.name, ", Salary: ", self.salary"This would create first object of Employee class"emp1 = Employee("Zara", 2000)"This would create second object of Employee class"emp2 = Employee("Manni", 5000)emp1.displayEmployee()emp2.displayEmployee()print "Total Employee %d" % Employee.empCount

Wanneer de bovenstaande code wordt uitgevoerd, levert dat het volgende resultaat op –

Name : Zara ,Salary: 2000Name : Manni ,Salary: 5000Total Employee 2

Je kunt attributen van klassen toevoegen, verwijderen, of attributen van klassen en objecten op elk gewenst moment wijzigen –

emp1.age = 7 # Add an 'age' attribute.emp1.age = 8 # Modify 'age' attribute.del emp1.age # Delete 'age' attribute.

In plaats van de normale statements te gebruiken om attributen te openen, kun je de volgende functies gebruiken –

  • De getattr(obj, naam) – om het attribuut van object te openen.

  • De hasattr(obj,naam) – om te controleren of een attribuut al dan niet bestaat.

  • De setattr(obj,naam,waarde) – om een attribuut in te stellen. Als het attribuut niet bestaat, wordt het aangemaakt.

  • De delattr(obj, naam) – om een attribuut te verwijderen.

hasattr(emp1, 'age') # Returns true if 'age' attribute existsgetattr(emp1, 'age') # Returns value of 'age' attributesetattr(emp1, 'age', 8) # Set attribute 'age' at 8delattr(empl, 'age') # Delete attribute 'age'

Ingebouwde klasse-attributen

Elke Python-klasse heeft de volgende ingebouwde attributen en deze kunnen net als elk ander attribuut met de dot-operator worden geopend –

  • __dict__ – Woordenboek dat de naamruimte van de klasse bevat.

  • __doc__ – Documentatiestring van de klasse of geen, indien ongedefinieerd.

  • __name__ – Naam van de klasse.

  • __module__ – Naam van de module waarin de klasse wordt gedefinieerd. Dit attribuut is “__main__” in de interactieve modus.

  • __bases__ – Een mogelijk lege tupel die de basisklassen bevat, in de volgorde waarin ze voorkomen in de lijst met basisklassen.

Proberen we voor de bovenstaande klasse toegang te krijgen tot al deze attributen –

#!/usr/bin/pythonclass Employee: 'Common base class for all employees' empCount = 0 def __init__(self, name, salary): self.name = name self.salary = salary Employee.empCount += 1 def displayCount(self): print "Total Employee %d" % Employee.empCount def displayEmployee(self): print "Name : ", self.name, ", Salary: ", self.salaryprint "Employee.__doc__:", Employee.__doc__print "Employee.__name__:", Employee.__name__print "Employee.__module__:", Employee.__module__print "Employee.__bases__:", Employee.__bases__print "Employee.__dict__:", Employee.__dict__

Wanneer de bovenstaande code wordt uitgevoerd, levert dat het volgende resultaat op –

Employee.__doc__: Common base class for all employeesEmployee.__name__: EmployeeEmployee.__module__: __main__Employee.__bases__: ()Employee.__dict__: {'__module__': '__main__', 'displayCount':<function displayCount at 0xb7c84994>, 'empCount': 2, 'displayEmployee': <function displayEmployee at 0xb7c8441c>, '__doc__': 'Common base class for all employees', '__init__': <function __init__ at 0xb7c846bc>}

Verwijderen van objecten (Garbage Collection)

Python verwijdert automatisch onnodige objecten (ingebouwde typen of klasse-instanties) om geheugenruimte vrij te maken. Het proces waarbij Python periodiek blokken geheugen terugwint die niet langer in gebruik zijn, wordt Garbage Collection genoemd.

Python’s garbage collector draait tijdens de uitvoering van het programma en wordt geactiveerd wanneer het aantal verwijzingen van een object nul bereikt. Het aantal verwijzingen naar een object verandert als het aantal aliassen verandert

Het aantal verwijzingen naar een object neemt toe als het een nieuwe naam krijgt of in een container wordt geplaatst (lijst, tuple of dictionary). Het aantal verwijzingen naar een object neemt af als het wordt verwijderd met del, als de verwijzing opnieuw wordt toegewezen, of als de verwijzing buiten bereik gaat. Wanneer het aantal verwijzingen van een object nul bereikt, wordt het automatisch door Python opgehaald.

a = 40 # Create object <40>b = a # Increase ref. count of <40> c = # Increase ref. count of <40> del a # Decrease ref. count of <40>b = 100 # Decrease ref. count of <40> c = -1 # Decrease ref. count of <40> 

Je zult normaal gesproken niet merken wanneer de vuilnisman een verweesde instantie vernietigt en zijn ruimte terugwint. Maar een klasse kan de speciale methode __del__() implementeren, een destructor genoemd, die wordt aangeroepen wanneer de instantie op het punt staat te worden vernietigd. Deze methode kan worden gebruikt om alle niet in het geheugen opgeslagen bronnen die door een instantie worden gebruikt, op te ruimen.

Voorbeeld

Deze __del__() destructor drukt de class name af van een instantie die op het punt staat te worden vernietigd –

#!/usr/bin/pythonclass Point: def __init__( self, x=0, y=0): self.x = x self.y = y def __del__(self): class_name = self.__class__.__name__ print class_name, "destroyed"pt1 = Point()pt2 = pt1pt3 = pt1print id(pt1), id(pt2), id(pt3) # prints the ids of the obejctsdel pt1del pt2del pt3

Wanneer de bovenstaande code wordt uitgevoerd, levert dit het volgende resultaat op –

3083401324 3083401324 3083401324Point destroyed

Note – Idealiter zou je je klassen in een apart bestand moeten definiëren, dan zou je ze moeten importeren in je hoofdprogrammabestand met behulp van import statement.

Klasse overerving

In plaats van helemaal opnieuw te beginnen, kunt u een klasse maken door deze af te leiden van een reeds bestaande klasse door de bovenliggende klasse tussen haakjes na de nieuwe klasse naam te vermelden.

De child klasse erft de attributen van zijn bovenliggende klasse, en u kunt deze attributen gebruiken alsof ze in de child klasse zijn gedefinieerd. Een child class kan ook data members en methods van de parent overriden.

Syntax

Afgeleide klassen worden op dezelfde manier gedeclareerd als hun bovenliggende klasse; echter, een lijst van basis klassen om van te erven wordt gegeven na de klasse naam –

class SubClassName (ParentClass1): 'Optional class documentation string' class_suite

Example

#!/usr/bin/pythonclass Parent: # define parent class parentAttr = 100 def __init__(self): print "Calling parent constructor" def parentMethod(self): print 'Calling parent method' def setAttr(self, attr): Parent.parentAttr = attr def getAttr(self): print "Parent attribute :", Parent.parentAttrclass Child(Parent): # define child class def __init__(self): print "Calling child constructor" def childMethod(self): print 'Calling child method'c = Child() # instance of childc.childMethod() # child calls its methodc.parentMethod() # calls parent's methodc.setAttr(200) # again call parent's methodc.getAttr() # again call parent's method

Wanneer de bovenstaande code wordt uitgevoerd, geeft dit het volgende resultaat –

Calling child constructorCalling child methodCalling parent methodParent attribute : 200

Op dezelfde manier, kun je een klasse uit meerdere bovenliggende klassen als volgt aansturen –

class A: # define your class A.....class B: # define your class B.....class C(A, B): # subclass of A and B.....

Je kunt issubclass() of isinstance() functies gebruiken om een relatie van twee klassen en instanties te controleren.

  • De booleaanse functie issubclass(sub, sup) retourneert true als de opgegeven subklasse sub inderdaad een subklasse is van de superklasse sup.

  • De boolean functie isinstance(obj, Class) geeft de waarde waar als obj een instantie van de klasse Class is of een instantie van een subklasse van Class

Overriding Methods

Je kunt de methoden van je hoofdklasse altijd overriden. Een reden om methoden van de ouderklasse te overschrijven is dat je misschien speciale of andere functionaliteit in je subklasse wilt.

Voorbeeld

#!/usr/bin/pythonclass Parent: # define parent class def myMethod(self): print 'Calling parent method'class Child(Parent): # define child class def myMethod(self): print 'Calling child method'c = Child() # instance of childc.myMethod() # child calls overridden method

Wanneer de bovenstaande code wordt uitgevoerd, levert dat het volgende resultaat op –

Calling child method

Base Overloading Methods

In de volgende tabel staan enkele generieke functionaliteiten die je in je eigen klassen kunt overriden –

Sr.No. Methode, Beschrijving & Voorbeeldoproep
1

__init__ ( self )

Constructor (met eventuele optionele argumenten)

Een voorbeeldoproep : obj = className(args)

2

__del__( self )

Destructor, verwijdert een object

Een voorbeeldoproep : del obj

3

__repr__( self )

Evalueerbare string-representatie

Voorbeeldoproep : repr(obj)

4

__str__( self )

Printable string representation

Sample Call : str(obj)

5

__cmp__ ( self, x )

Vergelijking van objecten

Voorbeeldoproep : cmp(obj, x)

Overloading Operators

Stel dat je een Vectorklasse hebt gemaakt om tweedimensionale vectoren weer te geven, wat gebeurt er dan als je de plus-operator gebruikt om ze op te tellen? Waarschijnlijk schreeuwt Python dan tegen je.

U zou echter de methode __add__ in uw klasse kunnen definiëren om vectoren op te tellen en dan zou de plus-operator zich gedragen zoals verwacht –

Exemplaar

#!/usr/bin/pythonclass Vector: def __init__(self, a, b): self.a = a self.b = b def __str__(self): return 'Vector (%d, %d)' % (self.a, self.b) def __add__(self,other): return Vector(self.a + other.a, self.b + other.b)v1 = Vector(2,10)v2 = Vector(5,-2)print v1 + v2

Wanneer de bovenstaande code wordt uitgevoerd, geeft dit het volgende resultaat –

Vector(7,8)

Data Hiding

De attributen van een object kunnen wel of niet zichtbaar zijn buiten de klasse definitie. Je moet attributen een naam geven met een dubbele underscore prefix, en die attributen zijn dan niet direct zichtbaar voor buitenstaanders.

Example

#!/usr/bin/pythonclass JustCounter: __secretCount = 0 def count(self): self.__secretCount += 1 print self.__secretCountcounter = JustCounter()counter.count()counter.count()print counter.__secretCount

Wanneer de bovenstaande code wordt uitgevoerd, levert dat het volgende resultaat op –

12Traceback (most recent call last): File "test.py", line 12, in <module> print counter.__secretCountAttributeError: JustCounter instance has no attribute '__secretCount'

Python beschermt die leden door intern de naam te veranderen zodat de naam van de klasse erin wordt opgenomen. Je kunt zulke attributen benaderen als object._className__attrName. Als u de laatste regel als volgt vervangt, dan werkt het voor u –

.........................print counter._JustCounter__secretCount

Wanneer de bovenstaande code wordt uitgevoerd, levert dat het volgende resultaat op –

Laat een reactie achter

Het e-mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *