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 u een expert te worden in het gebruik van Python’s object-georiënteerde programmeerondersteuning.

Als u geen eerdere ervaring heeft met object-georiënteerd (OO) programmeren, kunt u misschien beter een inleidende cursus over dit onderwerp raadplegen of op zijn minst een of andere tutorial, zodat u de basisconcepten onder de knie heeft.

Hoe dan ook, hier is 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 set attributen definieert die elk object van de klasse karakteriseert. De attributen zijn gegevensleden (klassevariabelen en instantievariabelen) 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 instantievariabelen.

  • Gegevenslid – Een klassevariabele of instantievariabele 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 is 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 – De creatie van een instantie van een klasse.

  • Method – 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 sleutelwoord 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 u een nieuwe instantie van deze klasse creëert.

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

Aanmaken van instantie-objecten

Om instanties van een klasse aan te maken, 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. Klassevariabelen worden als volgt benaderd met de naam van de klasse –

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

Wanneer nu alle concepten worden 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 bovenstaande code wordt uitgevoerd, levert dat het volgende resultaat op –

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

Je kunt attributen van klassen en objecten toevoegen, verwijderen, of attributen van klassen en objecten 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 toegang te krijgen tot attributen, kunt u de volgende functies gebruiken –

  • De getattr(obj, name) – om toegang te krijgen tot het attribuut van object.

  • 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 worden geopend met behulp van de dot-operator –

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

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

  • __name__ – Klassenaam.

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

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

Laten we voor de bovenstaande klasse eens proberen om 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 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>}

Vernietigen van objecten (Garbage Collection)

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>}

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 de referentietelling van een object nul bereikt. Het aantal verwijzingen naar een object verandert als het aantal aliassen dat ernaar verwijst verandert.

Het aantal verwijzingen naar een object neemt toe als het een nieuwe naam krijgt of in een container (lijst, tuple of dictionary) wordt geplaatst. 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 het bereik valt. Wanneer de reference count van een object nul bereikt, haalt Python het automatisch op.

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 merkt het normaal gesproken niet wanneer de garbage collector een orphaned instance 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.

Example

Deze __del__() destructor print de class name 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 dat het volgende resultaat op –

3083401324 3083401324 3083401324Point destroyed

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

Klass Inheritance

In plaats van vanaf nul te beginnen, kunt u een class maken door deze af te leiden van een reeds bestaande class door de parent class tussen haakjes achter de nieuwe class naam te zetten.

De child class erft de attributen van zijn parent class, en u kunt deze attributen gebruiken alsof ze in de child class gedefinieerd waren. Een kind klasse kan ook override gegevens leden en methoden van de ouder.

Syntax

Afgeleide klassen worden op dezelfde manier gedeclareerd als hun bovenliggende klasse; echter, een lijst van basisklassen 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 het het volgende resultaat –

Calling child constructorCalling child methodCalling parent methodParent attribute : 200

Op dezelfde manier, kunt u een klasse van meerdere ouderklassen als volgt besturen –

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

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

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

  • De boolean functie isinstance(obj, Class) is 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 van de redenen om de methoden van de bovenliggende klasse te overschrijven, is dat u misschien speciale of andere functionaliteit in uw 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 vindt u enkele generieke functionaliteiten die u in uw eigen klassen kunt overschrijven –

Sr.nr. Methode, Beschrijving & Voorbeeldoproep
1

__init__ ( self )

Constructor (met eventuele optionele argumenten)

Voorbeeldoproep : obj = className(args)

2

__del__( self )

Destructor, verwijdert een object

Oproepvoorbeeld : del obj

3

__repr__( self )

Evalueerbare tekenreeksrepresentatie

Sample Call : repr(obj)

4

__str__( self )

Printable string representation

Sample Call : str(obj)

5

__cmp__ ( self, x )

Vergelijking van objecten

Proefaanroep : 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? Hoogstwaarschijnlijk zal Python tegen je schreeuwen.

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 –

Voorbeeld

#!/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, levert dat het volgende resultaat op –

Vector(7,8)

Data Hiding

Vector(7,8)

Data Hiding

De attributen van een object kunnen al dan niet zichtbaar zijn buiten de definitie van de klasse. 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 om de naam van de klasse op te nemen. 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 –

Geef een antwoord

Het e-mailadres wordt niet gepubliceerd.