Python – objektorienterad

Vannonser

Python har varit ett objektorienterat språk sedan det började existera. På grund av detta är det rent av enkelt att skapa och använda klasser och objekt. Det här kapitlet hjälper dig att bli expert på att använda Pythons stöd för objektorienterad programmering.

Om du inte har någon tidigare erfarenhet av objektorienterad (OO) programmering kan du läsa en introduktionskurs i ämnet eller åtminstone en handledning av något slag, så att du får ett grepp om de grundläggande begreppen.

Hursomhelst, här är en liten introduktion av objektorienterad programmering (OOP) för att få dig i fart –

Översikt över OOP-terminologi

  • Klass – En användardefinierad prototyp för ett objekt som definierar en uppsättning attribut som karakteriserar alla objekt i klassen. Attributen är datamedlemmar (klassvariabler och instansvariabler) och metoder som nås via punktnotering.

  • Klassvariabel – En variabel som delas av alla instanser av en klass. Klassvariabler definieras inom en klass men utanför någon av klassens metoder. Klassvariabler används inte lika ofta som instansvariabler.

  • Datamedlem – En klassvariabel eller instansvariabel som innehåller data som är kopplade till en klass och dess objekt.

  • Funktionsöverladdning – Tilldelning av mer än ett beteende till en viss funktion. Den operation som utförs varierar beroende på vilka typer av objekt eller argument som berörs.

  • Instansvariabel – En variabel som definieras inne i en metod och som endast tillhör den aktuella instansen av en klass.

  • Arv – Överföring av en klass’ egenskaper till andra klasser som är härledda från den.

  • Instans – Ett enskilt objekt av en viss klass. Ett objekt obj som tillhör en klass Circle är till exempel en instans av klassen Circle.

  • Instantiering – Skapandet av en instans av en klass.

  • Metod – En speciell typ av funktion som definieras i en klassdefinition.

  • Objekt – En unik instans av en datastruktur som är definierad av sin klass. Ett objekt omfattar både datamedlemmar (klassvariabler och instansvariabler) och metoder.

  • Operatoröverladdning – Tilldelning av mer än en funktion till en viss operatör.

Skapa klasser

Med class-angivelsen skapas en ny klassdefinition. Klassens namn följer omedelbart efter nyckelordet class följt av ett kolon enligt följande –

class ClassName: 'Optional class documentation string' class_suite
  • Klassen har en dokumentationssträng som kan nås via ClassName.__doc__.

  • Klassuppsättningen består av alla komponentdeklarationer som definierar klassmedlemmar, dataattribut och funktioner.

Exempel

Nedan följer ett exempel på en enkel Pythonklass –

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
  • Variabeln empCount är en klassvariabel vars värde delas mellan alla instanser av en denna klass. Den kan nås som Employee.empCount från inne i klassen eller utanför klassen.

  • Den första metoden __init__() är en speciell metod, som kallas klasskonstruktör eller initialiseringsmetod som Python anropar när du skapar en ny instans av den här klassen.

  • Du deklarerar andra klassmetoder som vanliga funktioner med undantaget att det första argumentet till varje metod är self. Python lägger till argumentet self i listan åt dig; du behöver inte inkludera det när du anropar metoderna.

Skapa instansobjekt

För att skapa instanser av en klass anropar du klassen med hjälp av class name och skickar in de argument som dess __init__-metod accepterar.

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

Accessing Attributes

Du har åtkomst till objektets attribut med hjälp av dot-operatorn med object. Klassvariabeln nås med hjälp av klassnamnet på följande sätt –

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

Nu, om man sätter ihop alla begrepp –

#!/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

När ovanstående kod exekveras ger den följande resultat –

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

Du kan lägga till, ta bort, eller ändra attribut för klasser och objekt när som helst –

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

Istället för att använda normala uttalanden för att få tillgång till attribut kan du använda följande funktioner –

  • Getattr(obj, name) – för att få tillgång till attributet för objektet.

  • The hasattr(obj,name) – för att kontrollera om ett attribut finns eller inte.

  • The setattr(obj,name,value) – för att ange ett attribut. Om attributet inte finns, skapas det.

  • The delattr(obj, name) – för att ta bort ett attribut.

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'

Inbyggda klassattribut

Alla Python-klasser har följande inbyggda attribut och de kan nås med hjälp av punktoperatorn som vilket annat attribut som helst –

  • __dict__ – Ordbok som innehåller klassens namnområde.

  • __doc__ – Sträng för klassdokumentation eller ingen om den inte är definierad.

  • __name____ – Klassens namn.

  • __module__ – Modulnamn där klassen är definierad. Detta attribut är ”__main__” i interaktivt läge.

  • __bases__ – En eventuellt tom tupel som innehåller basklasserna, i den ordning de förekommer i basklasslistan.

För klassen ovan ska vi försöka få tillgång till alla dessa attribut –

#!/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__

När koden ovan exekveras ger den följande resultat –

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

Destruering av objekt (Garbage Collection)

Python raderar obehövliga objekt (inbyggda typer eller klassinstanser) automatiskt för att frigöra minnesutrymme. Processen genom vilken Python periodiskt återtar minnesblock som inte längre används kallas Garbage Collection.

Pythons garbage collector körs under programutförandet och utlöses när ett objekts referensantal når noll. Ett objekts referensantal ändras när antalet alias som pekar på det ändras.

Ett objekts referensantal ökar när det tilldelas ett nytt namn eller placeras i en behållare (lista, tupel eller ordbok). Objektets referensantal minskar när det tas bort med del, dess referens tilldelas på nytt eller när dess referens går utanför räckvidden. När ett objekts referensantal når noll samlar Python in det automatiskt.

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> 

Du kommer normalt inte att märka när garbage collector förstör en föräldralös instans och återtar dess utrymme. Men en klass kan implementera den speciella metoden __del__(), kallad destructor, som anropas när instansen är på väg att förstöras. Den här metoden kan användas för att städa upp alla icke-minnesresurser som används av en instans.

Exempel

Denna __del__()-destruktor skriver ut klassnamnet på en instans som är på väg att förstöras –

#!/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

När ovanstående kod exekveras ger den följande resultat –

3083401324 3083401324 3083401324Point destroyed

Anm. – Helst bör du definiera dina klasser i en separat fil och sedan importera dem i din huvudprogramfil med hjälp av import-anvisning.

Klassarv

Istället för att börja från början kan du skapa en klass genom att härleda den från en redan existerande klass genom att ange den överordnade klassen inom parentes efter det nya klassnamnet.

Den underordnade klassen ärver attribut från den överordnade klassen och du kan använda dessa attribut som om de hade definierats i den underordnade klassen. En barnklass kan också åsidosätta datamedlemmar och metoder från den överordnade klassen.

Syntax

Avledda klasser deklareras på samma sätt som föräldraklassen; dock ges en lista över basklasser att ärva från efter klassnamnet –

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

Exempel

#!/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

När ovanstående kod exekveras får man följande resultat –

Calling child constructorCalling child methodCalling parent methodParent attribute : 200

På samma sätt kan man driva en klass från flera överordnade klasser på följande sätt –

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

Du kan använda funktionerna issubclass() eller isinstance() för att kontrollera ett samband mellan två klasser och instanser.

  • Den booleska funktionen issubclass(sub, sup) returnerar sant om den givna underklassen sub verkligen är en underklass till överklassen sup.

  • Den booleska funktionen isinstance(obj, Class) returnerar sant om obj är en instans av klassen Class eller är en instans av en underklass av Class

Overriding Methods

Du kan alltid överordna dina överordnade klassmetoder. En anledning till att överskriva förälderns metoder är att du kanske vill ha speciell eller annorlunda funktionalitet i din underklass.

Exempel

#!/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

När ovanstående kod exekveras får du följande resultat –

Calling child method

Base Overloading Methods

Följande tabell listar en del generisk funktionalitet som du kan överskriva i dina egna klasser –

Sr.No. Metod, Beskrivning & Exempel på anrop
1

__init__ ( self )

Konstruktör (med valfria argument)

Exempel på anrop :

2

__del__( self )

Destructor, raderar ett objekt

Exempel på anrop: del obj

3

__repr__( self )

Värderbar strängrepresentation

Exempel på anrop: repr(obj)

4

__str__( self )

Utskrivbar strängrepresentation

Exempel på anrop: str(obj)

5

__cmp__ ( self, x )

Objektjämförelse

Exempel på anrop: cmp(obj, x)

Överbelastning av operatorer

Antag att du har skapat en Vector-klass för att representera tvådimensionella vektorer, vad händer när du använder plus-operatorn för att addera dem? Troligtvis kommer Python att skrika åt dig.

Du kan dock definiera metoden __add__ i din klass för att utföra vektoraddition och då skulle plusoperatorn bete sig som förväntat –

Exempel

#!/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

När ovanstående kod exekveras får du följande resultat –

Vector(7,8)

Dataskydd

Ett objekts attribut kan vara synliga eller inte utanför klassdefinitionen. Du måste namnge attributen med ett prefix med dubbel understrykning, och dessa attribut är då inte direkt synliga för utomstående.

Exempel

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

När ovanstående kod exekveras får du följande resultat –

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

Python skyddar dessa medlemmar genom att internt ändra namnet så att det inkluderar klassens namn. Du kan få tillgång till sådana attribut som object._className__attrName. Om du byter ut den sista raden mot följande fungerar det –

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

När ovanstående kod exekveras får du följande resultat –

Lämna ett svar

Din e-postadress kommer inte publiceras.