Python – Oliosuuntautunut

Esittelyt

Python on ollut oliosuuntautunut kieli olemassaolostaan lähtien. Tästä johtuen luokkien ja objektien luominen ja käyttäminen on suorastaan helppoa. Tämän luvun avulla sinusta tulee asiantuntija Pythonin olio-ohjelmointituen käytössä.

Jos sinulla ei ole aiempaa kokemusta olio-ohjelmoinnista (OO-ohjelmoinnista), sinun kannattaa tutustua johonkin sitä käsittelevään johdantokurssiin tai ainakin jonkinlaiseen opetusohjelmaan, jotta sinulla on käsitys peruskäsitteistä.

Tässä kuitenkin pieni johdanto oliokeskeisestä ohjelmoinnista (OOP), jotta pääset vauhtiin –

Yleiskatsaus OOP-terminologiaan

  • Luokka – Käyttäjän määrittelemä objektin prototyyppi, joka määrittelee joukon attribuutteja, jotka luonnehtivat mitä tahansa luokan objektia. Attribuutit ovat datajäseniä (luokkamuuttujat ja instanssimuuttujat) ja metodeja, joihin päästään käsiksi pistemerkinnällä.

  • Luokkamuuttuja – Muuttuja, joka on kaikkien luokan instanssien yhteinen. Luokkamuuttujat määritellään luokan sisällä, mutta luokkametodien ulkopuolella. Luokkamuuttujia ei käytetä yhtä usein kuin instanssimuuttujia.

  • Data member – Luokkamuuttuja tai instanssimuuttuja, joka sisältää luokkaan ja sen objekteihin liittyviä tietoja.

  • Funktion ylikuormitus – Useamman kuin yhden käyttäytymisen osoittaminen tietylle funktiolle. Suoritettu toiminto vaihtelee kyseessä olevien objektien tai argumenttien tyypin mukaan.

  • Instanssimuuttuja – Muuttuja, joka on määritelty metodin sisällä ja joka kuuluu vain luokan senhetkiseen instanssiin.

  • Perinnöllisyys – Luokan ominaisuuksien siirtyminen muihin luokkiin, jotka on johdettu siitä.

  • Instanssi – Tietyn luokan yksittäinen objekti. Esimerkiksi luokkaan Circle kuuluva obj-olio on luokan Circle instanssi.

  • Instantiointi – Luokan instanssin luominen.

  • Menetelmä – Erikoislaatuinen funktio, joka on määritelty luokkamääritelmässä.

  • Objekti – Luokkansa määrittelemän tietorakenteen yksilöllinen instanssi. Olio käsittää sekä datajäsenet (luokkamuuttujat ja instanssimuuttujat) että metodit.

  • Operaattorin ylikuormitus – Useamman kuin yhden funktion osoittaminen tietylle operaattorille.

Luokkien luominen

Luokka-lausekkeella luodaan uusi luokkamäärittely. Luokan nimi seuraa välittömästi avainsanaa class, jota seuraa kaksoispiste seuraavasti –

class ClassName: 'Optional class documentation string' class_suite
  • Luokalla on dokumentaatio-merkkijono, johon pääsee käsiksi komennolla ClassName.__doc__.

  • Luokan_suite koostuu kaikista komponenttilausekkeista, joissa määritellään luokan jäsenet, data-attribuutit ja funktiot.

Esimerkki

Seuraava on esimerkki yksinkertaisesta Python-luokasta –

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
  • Muuttuja empCount on luokkamuuttuja, jonka arvo jaetaan kaikkien tämän luokan instanssien kesken. Sitä voidaan käyttää nimellä Employee.empCount luokan sisältä tai luokan ulkopuolelta.

  • Ensimmäinen metodi __init__() on erityinen metodi, jota kutsutaan luokan konstruktoriksi tai alustamismetodiksi, jota Python kutsuu, kun luodaan uusi instanssi tästä luokasta.

  • Muut luokkametodit julistetaan kuten tavalliset funktiot sillä erotuksella, että jokaisen metodin ensimmäinen argumentti on self. Python lisää self-argumentin listaan puolestasi; sinun ei tarvitse sisällyttää sitä, kun kutsut metodeja.

Objektien instanssien luominen

Luodaksesi luokan instansseja kutsut luokkaa käyttämällä luokan nimeä ja annat luokalle ne argumentit, jotka sen __init__-metodi hyväksyy.

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

Ammattimerkkien käyttäminen

Käyttöönotat objektien attribuutteja piste-operaattorilla, jonka kanssa käytetään kohdetta (dot operator) object. Luokan muuttujaa käytettäisiin luokan nimellä seuraavasti –

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

Nyt, kun laitetaan kaikki käsitteet yhteen –

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

Kun yllä oleva koodi suoritetaan, se tuottaa seuraavan tuloksen –

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

Voit lisätä, poistaa, tai muuttaa luokkien ja objektien attribuutteja milloin tahansa –

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

Normaalien lausekkeiden käyttämisen sijasta voit käyttää seuraavia funktioita –

  • Getattr(obj, nimi) – käyttää objektin attribuuttia.

  • The hasattr(obj,name) – tarkistaa, onko attribuutti olemassa vai ei.

  • The setattr(obj,name,value) – asettaa attribuutin. Jos attribuuttia ei ole olemassa, se luodaan.

  • The delattr(obj, name) – attribuutin poistamiseksi.

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'

Luokan sisäänrakennetut attribuutit

Jokainen Python-luokka pitää seuraavat sisäänrakennetut attribuutit ja niitä voidaan käyttää piste-operaattorilla kuten mitä tahansa muuta attribuuttia –

  • __dict__ – Sanakirja, joka sisältää luokan nimiavaruuden.

  • __doc__ – Luokan dokumentaatio-merkkijono tai ei mitään, jos se on määrittämättä.

  • __name__ – Luokan nimi.

  • __module__ – Moduulin nimi, jossa luokka on määritelty. Tämä määrite on ”__main__” interaktiivisessa tilassa.

  • __bases__ – Mahdollisesti tyhjä tuple, joka sisältää perusluokat siinä järjestyksessä kuin ne esiintyvät perusluokkien luettelossa.

Ylläolevan luokan osalta yritetään käyttää kaikkia näitä attribuutteja –

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

Kun ylläoleva koodi suoritetaan, se tuottaa seuraavan tuloksen –

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

Objektien tuhoaminen (roskienkeruu)

Python poistaa tarpeettomia objekteja (sisäänrakennettuja tyyppejä tai luokkien instansseja) automaattisesti vapauttaakseen muistia. Prosessia, jolla Python ottaa määräajoin takaisin muistilohkoja, joita ei enää käytetä, kutsutaan roskienkeräykseksi.

Pythonin roskienkerääjä toimii ohjelman suorituksen aikana ja käynnistyy, kun objektin viittausluku saavuttaa nollan. Objektin viittausluku muuttuu, kun siihen viittaavien aliasien määrä muuttuu.

Objektin viittausluku kasvaa, kun sille annetaan uusi nimi tai se sijoitetaan säiliöön (lista, tuple tai sanakirja). Objektin viittausluku pienenee, kun se poistetaan del-käskyllä, sen viittaus osoitetaan uudelleen tai sen viittaus poistuu soveltamisalan ulkopuolelle. Kun objektin viittausluku saavuttaa nollan, Python kerää sen automaattisesti pois.

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> 

Et yleensä huomaa, kun roskienkerääjä tuhoaa orvoksi jääneen instanssin ja ottaa sen tilan takaisin. Mutta luokka voi toteuttaa erityisen metodin __del__(), jota kutsutaan destruktoriksi ja jota kutsutaan, kun instanssi on tuhoutumassa. Tätä metodia voidaan käyttää siivoamaan kaikki instanssin käyttämät muut kuin muistiresurssit.

Esimerkki

Tämä __del__() destruktori tulostaa tuhoutumassa olevan instanssin luokan nimen –

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

Kun ylläoleva koodi suoritetaan, se tuottaa seuraavan tuloksen –

3083401324 3083401324 3083401324Point destroyed

Huomautus – Ihannetapauksessa luokat kannattaa määritellä erillisessä tiedostossa, jonka jälkeen ne tuodaan import-lausekkeella pääohjelmatiedostoon.

Luokan periytyminen

Sen sijaan, että aloittaisit tyhjästä, voit luoda luokan derivoimalla sen jo olemassa olevasta luokasta luettelemalla vanhemman luokan suluissa uuden luokan nimen perässä.

Lapsi-luokka perii vanhemman luokkansa attribuutit, ja voit käyttää näitä attribuutteja ikään kuin ne olisi määritelty lapsiluokassa. Lapsiluokka voi myös ohittaa vanhemman luokan datajäsenet ja metodit.

Syntaksi

Johdetut luokat julistetaan samalla tavalla kuin niiden vanhempaluokka; mutta luokan nimen jälkeen annetaan kuitenkin luettelo perusluokista, joista periytyä –

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

Esimerkki

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

Kun yllä oleva koodi suoritetaan, se tuottaa seuraavan tuloksen –

Calling child constructorCalling child methodCalling parent methodParent attribute : 200

Samalla tavalla voit ajaa luokan useammasta vanhemmasta luokasta seuraavasti –

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

Kahden luokan ja instanssin suhteiden tarkistamiseen voit käyttää issubclass()- tai isinstance()-funktioita.

  • Boolefunktio issubclass(sub, sup) palauttaa arvon true, jos annettu alaluokka sub on todellakin yläluokan sup alaluokka.

  • The isinstance(obj, Class) boolean function returns true if obj is an instance of class Class or is an instance of a subclass of Class

Overriding Methods

Voit aina ohittaa vanhemman luokan metodeja. Yksi syy vanhemman luokan metodien ylikirjoittamiseen on se, että saatat haluta alaluokassasi erityistä tai erilaista toiminnallisuutta.

Esimerkki

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

Kun yllä oleva koodi suoritetaan, se tuottaa seuraavan tuloksen –

Calling child method

Perusluokan ylikirjoittavat metodit

Seuraavassa taulukossa on lueteltu joitain yleisiä toiminnallisuuksia, jotka voit ylikirjoittaa omissa luokissasi –

Sr.nro. Metodi, Kuvaus & Esimerkkikutsu
1

__init__ ( self )

Konstruktori (mahdollisine valinnaisargumentteineen)

Esimerkkikutsu : obj = className(args)

2

__del__( self )

Destruktori, poistaa objektin

Sample Call : del obj

3

__repr__( self )

Arvioidaan merkkijonon esitys

Sample Call : repr(obj)

4

__str__( self )

Tulostettava merkkijonoesitys

Sample Call : str(obj)

5

__cmp__ ( self, x )

Objektien vertailu

Sample Call : cmp(obj, x)

Operaattoreiden ylikuormittaminen

Asettele, että olet luonut Vector-luokan esittämään kaksiulotteisia vektoreita, mitä tapahtuu, kun käytät plus-operaattoria niiden yhteenlaskuun? Todennäköisesti Python huutaa sinulle.

Voisit kuitenkin määritellä luokassasi __add__-metodin suorittamaan vektorien yhteenlaskun, jolloin plus-operaattori käyttäytyisi odotusten mukaisesti –

Esimerkki

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

Kun ylläoleva koodi suoritetaan, se tuottaa seuraavan tuloksen –

Vector(7,8)

Datan piilottaminen

Objektin attribuutit voivat näkyä tai sitten eivät näy luokkamäärittelyn ulkopuolella. Attribuutit pitää nimetä kaksoisalaviivalla etuliitteellä, jolloin ne eivät ole suoraan ulkopuolisten nähtävissä.

Esimerkki

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

Kun yllä oleva koodi suoritetaan, se tuottaa seuraavan tuloksen –

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

Python suojaa näitä jäseniä muuttamalla sisäisesti nimen sisältämään luokan nimen. Voit käyttää tällaisia attribuutteja muodossa object._className__attrName. Jos korvaisit viimeisen rivisi seuraavasti, niin se toimii sinulle –

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

Kun yllä oleva koodi suoritetaan, se tuottaa seuraavan tuloksen –

Vastaa

Sähköpostiosoitettasi ei julkaista.