Python fra scratch Objektorientert programmering

Velkommen tilbake til leksjonen fire i vår Python fra grunnen serie. Denne opplæringen tar utgangspunkt i tidligere kunnskap om variabler, datatyper, funksjoner og utskriftsutgang. Hvis du ikke er oppdatert, sjekk ut de tre foregående artiklene i serien for å hente opp.

I dag kommer vi til å være delving i emnet Object Oriented Programming (OOP). OOP er en veldig kraftig måte å organisere koden på, og en solid forståelse av konseptene bak den kan virkelig hjelpe deg med å få mest mulig ut av kodingen.


Foretrekker en Screencast?


transkripsjon


Hva er objektorientert programmering?

Python er primært utformet som et objektorientert programmeringsspråk - men hva betyr "objektorientert" faktisk?

Det finnes en rekke definisjoner for begrepet, og du kan snakke for bokstavelig tid å prøve å forklare de kompliserte innspillene, nyansene og forskjellene i implementeringer, men jeg vil prøve å gi en rask oversikt.

I det store og hele er objektorientert programmering konseptet om at objekter som vi manipulerer i programmeringen er viktigere enn logikken som trengs for å manipulere disse objektene. Tradisjonelt har et program blitt sett på som en oppskrift - et sett med instruksjoner som du følger fra start til slutt for å fullføre en oppgave. Det kan fortsatt være sant, og for mange enkle programmer er det alt som kreves. Denne tilnærmingen er noen ganger kjent som prosedyreprogrammering.

OOP setter objekter i sentrum av prosessen.

På den annen side, ettersom programmene blir mer og mer komplekse og innviklede, blir logikken som trengs for å skrive dem på en rent prosessorisk måte, mer og mer vridd og vanskelig å forstå. Ofte objektorienterte tilnærminger kan hjelpe med det.

Når vi snakker om objektorienterte tilnærminger, er det vi legger objektene i sentrum av prosessen, i stedet for bare å bruke dem som nødvendige beholdere for informasjon som en del av våre prosedyrinstruksjoner. Først definerer vi objektene vi vil manipulere og hvordan de forholder seg til hverandre, og så begynner vi å kutte det ut med logikk for å få programmet til å fungere..

Når jeg snakker om "objekter", kan jeg snakke om alle slags ting. Et objekt kan representere en person (som definert av egenskaper som navn, alder, adresse osv.), Eller et selskap (som definert av ting som antall ansatte osv.), Eller enda noe mye mer abstrakt, som en knappen i et datagrensesnitt.

I denne introduksjonen skal vi ikke dekke alle konseptene i dette emnet fordi vi ville være her hele natten, men ved slutten av opplæringen håper jeg at du får en solid forståelse av prinsippene du trenger å starte med en gang ved å bruke noen enkle objektorienterte teknikker i Python-programmene. Enda bedre, disse konseptene er ganske like i mange programmeringsmiljøer. Kunnskapen overfører fra språk til språk ganske pent.


Starter

Jeg nevnte tidligere at det første vi skal gjøre når vi går for en OOP-tilnærming er å definere objektene vi skal bruke. Måten vi gjør dette på er å først definere egenskapene som den besitter ved å bruke en klasse. Du kan tenke på en klasse som en slags mal; en veiledning for måten en gjenstand skal struktureres på. Hvert objekt tilhører en klasse og arver egenskapene til den klassen, men handler individuelt til de andre objektene i den klassen.

Et objekt er noen ganger referert til som en "forekomst" av en klasse.

Som et enkelt eksempel kan du ha en klasse som heter 'person' med, si en alder og en navnegenskap, og en forekomst av denne klassen (et objekt) ville være en enkelt person. Den personen kan ha et navn på? Andy? og en alder av 23, men du kan samtidig ha en annen person som tilhører samme klasse med navnet Lucy? og en alder av 18 år.

Det er vanskelig å forstå dette uten å se det i praksis, så la oss få noen faktisk kode som går.

Definere en klasse

For å definere en klasse, i typisk enkel Python-mote, bruker vi ordet 'klasse', etterfulgt av navnet på den nye klassen din. Jeg skal lage en ny klasse her, kalt "kjæledyr". Vi bruker et kolon etter navnet, og så er alt innhold i klassedepartementet innrykket. Men med en klasse er det ingen parenteser:

 klassen kjæledyr: 

Så nå har vi en klasse, men det er ganske ubrukelig uten noe i det. For å starte, la oss gi det et par egenskaper. For å gjøre dette, definerer du bare noen variabler i klassen - jeg skal gå med antall ben til å begynne med. Som vanlig bør du alltid nevne variablene dine slik at det er lett å fortelle hva de er. La oss være originale og kaller det 'number_of_legs'. Vi må definere en verdi, eller vi får en feil. Jeg bruker 0 her (det spiller ingen rolle for mye i dette tilfellet, siden antall ben vil være spesifikke for hver forekomst av klassen - en fisk har ikke samme mengde ben som en hund eller en and, etc. - så må vi endre verdien for hvert objekt uansett).

 klasse kjæledyr: number_of_legs = 0 

Forekomster og medlemsvariabler

En klasse i seg selv er ikke noe du kan manipulere direkte; Først må vi lage en forekomst av klassen for å leke med. Vi kan lagre den forekomsten i en variabel. Utenfor klassen (uten innrykk), la oss lage en forekomst av klassen og lagre den i variabelen, 'doug'. For å lage en ny forekomst av en klasse skriver du bare navnet på klassen, og deretter et par parenteser. På dette punktet er det ikke nødvendig å bekymre seg om parentesene, men senere ser du at de er der fordi, som en funksjon, det er en måte å overføre i en variabel for bruk av klassen når du først lager forekomsten.

En klasse i seg selv er ikke noe du kan manipulere direkte.

 klassen kjæledyr: number_of_legs = 0 doug = kjæledyr () 

Nå som vi har en forekomst av en klasse, hvordan får vi tilgang til og manipulere sine egenskaper? For å referere til en egenskap av et objekt, må vi først fortelle Python hvilken gjenstand (eller hvilken forekomst av en klasse) vi snakker om, så vi skal begynne med 'doug'. Deretter skal vi skrive en periode for å indikere at vi refererer til noe som finnes i vår doug-forekomst. Etter perioden legger vi til navnet på vår variabel. Hvis vi får tilgang til number_of_legs variabel, det kommer til å se slik ut:

 doug.number_of_legs 

Vi kan behandle det nå akkurat som vi ville behandle noen andre variabler - her skal jeg anta at doug er en hund, og vil gi den variabelen verdien av 4.

For å få tilgang til denne variabelen, skal vi bruke den på nytt akkurat som vi ville behandle andre variabler, men bruke det doug.number_of_legs eiendom i stedet for det normale variabelnavnet. La oss sette inn en linje for å skrive ut hvor mange ben doug har slik at vi kan vise at det fungerer som det skal:

 klassen kjæledyr: number_of_legs = 0 doug = pet () doug.number_of_legs = 4 print "Doug har% s ben." % doug.number_of_legs 

Hvis du kjører koden ovenfor, ser du at den er skrevet ut for oss. Det definerte vår "kjæledyr" klasse, opprettet en ny forekomst av denne klassen og lagret den i variabelen 'doug', og i så fall er den tildelt verdien av 4 til number_of_legs variabel at den arvet fra sin klasse.

Så du kan se fra det svært forenklede eksempelet hvordan du kan begynne å bygge flotte, modulære datastrukturer som er klare og enkle å bruke, og kan begynne å skalere ganske pent.


Innføring av logikk

Ok, så det er selve grunnleggende om klasser og objekter, men for øyeblikket kan vi bare virkelig bruke klasser som datastrukturer - eller, beholdere for variabler. Det er alt bra og bra, men hvis vi ønsker å begynne å utføre mer komplekse oppgaver med dataene vi manipulerer, trenger vi en måte å introdusere noen logikk inn i disse objektene. Måten vi gjør det er med metoder.

Metoder, i hovedsak, er funksjoner inneholdt i en klasse. Du definerer en på nøyaktig samme måte som du ville en funksjon, men forskjellen er at du legger den inne i en klasse, og den tilhører den klassen. Hvis du noen gang vil kalle den metoden, må du først referere til et objekt av denne klassen, akkurat som de variablene vi så på tidligere.

Metoder, i hovedsak, er funksjoner inneholdt i en klasse.

Jeg skal skrive et raskt eksempel her i vår kjæledyrklasse for å demonstrere; la oss lage en metode, kalt "søvn", som skal skrive ut en melding når den først blir kalt. Akkurat som en funksjon, skal jeg sette 'def' for 'define', og så skal jeg skrive navnet på metoden jeg vil lage. Da skal vi sette parentesene og semikolonene, og deretter starte en ny linje. Som vanlig er alt som inngår i denne metoden, inntrukket et ekstra nivå.

Nå er det en annen forskjell mellom en metode og en funksjon: En metode alltid, alltid, må alltid ha et argument, kalt "selv" mellom parentesene. Når Python kaller en metode, går det nåværende objekt til den metoden som det første argumentet. Med andre ord, når vi ringer doug.sleep (), Python kommer faktisk til å passere objektet 'doug' som et argument til søvnmetoden.

Vi ser hvorfor det er senere, men for nå må du vite at med en metode må du alltid inkludere et argument som heter "selv" først i listen (hvis du vil legge til flere argumenter, kan du legge til dem etterpå, akkurat som om du passerte flere argumenter til en funksjon). Hvis du ikke inkluderer det argumentet, når du kjører koden, kommer du til å få en feil kastet fordi Python passerer i et argument (dette "selv" -objektet), og metoden sier, "Hei, mann, Jeg tar ingen argumenter, hva snakker du om? '. Det er det samme som om du forsøkte å sende et argument til en funksjon som ikke aksepterer noen argumenter.

Så her er det vi har så langt:

 klasse kjæledyr: number_of_legs = 0 def sleep (selv): doug = kjæledyr () 

Innenfor denne metoden skal vi skrive en utskriftserklæring slik:

 klasse kjæledyr: number_of_legs = 0 def sleep (selv): print "zzz" doug = kjæledyr () 

Nå, hvis vi vil bruke denne metoden, bruker vi bare en forekomst av kjæledyrklassen for å referere den. Akkurat som number_of_legs variabel, skriver vi navnet på forekomsten (vi har en kalt doug), så en periode, deretter navnet på metoden, inkludert parenteser. Vær oppmerksom på at vi ringer søvn uten argumenter, men Python kommer til å legge til i det argumentet av seg selv, så vi kommer til å ende opp med den riktige mengden argumenter totalt.

 klassen kjæledyr: number_of_legs = 0 def sleep (selv): print "zzz" doug = pet () doug.sleep () 

Hvis du kjører denne koden, bør du se at den skriver ut meldingen vi skrev.

Data

Flott, så nå, hvordan skriver vi en ny metode for å skrive ut hvor mange bein kjæledyret har, for å demonstrere hvordan du kan bruke metoder for å begynne å manipulere dataene i klassen, og å vise hvorfor vi må inkludere dette forvirrende "selv" argument. La oss lage en ny metode, kalt 'count_legs'.

Dette er hvor "selv" argumentet kommer inn. Husk når vi åpnet number_of_legs fra utenfor klassen og vi måtte bruke 'doug.number_of_legs' i stedet for bare 'number_of_legs'? Det samme prinsippet gjelder; hvis vi vil vite hva som finnes i den variabelen, må vi referere det ved først å angi forekomsten som inneholder den variabelen.

Imidlertid vet vi ikke hva forekomsten skal kalles når vi skriver klassen, så vi kommer rundt det ved å bruke "selv" variabelen. 'selv' er bare en referanse til objektet som for tiden blir manipulert. Så for å få tilgang til en variabel i nåværende klasse, trenger du bare å forord det med "selv" og så en periode, slik som:

 klassen kjæledyr: number_of_legs = 0 def sleep (selv): print "zzz" def count_legs (selv): print "Jeg har% s ben"% self.number_of_legs doug = pet () doug.number_of_legs = 4 doug.count_legs 

I praksis betyr det at hvor du skriver "selv" i metoden din, når du kjører metoden som selv er erstattet av navnet på objektet, så når vi kaller doug.count_legs (), er "selvet" erstattet av 'doug'. For å demonstrere hvordan dette fungerer med flere forekomster, la vi legge til en andre forekomst, som representerer et annet kjæledyr, kalt 'nemo':

 klassen kjæledyr: number_of_legs = 0 def sleep (selv): print "zzz" def count_legs (selv): print "Jeg har% s ben"% self.number_of_legs doug = pet () doug.number_of_legs = 4 doug.count_legs () nemo = kjæledyr () nemo.number_of_legs = 0 nemo.count_legs () 

Dette vil skrive ut en melding for 4 og deretter 0 ben, akkurat som vi ønsket, fordi når vi kaller 'nemo.count_legs ()' erstattes 'selvet' med 'nemo' i stedet for 'doug'.

På denne måten vil vår metode kjøre akkurat som beregnet fordi "selvreferansen" vil endre seg dynamisk avhengig av konteksten og tillate oss å manipulere dataene bare innenfor det nåværende objektet.

De viktigste tingene du må huske om metoder er at de er akkurat som funksjoner, bortsett fra at det første argumentet må være "selv", og at for å referere til en intern variabel må du forord det variable navnet med "selv".

Bare som et notat: Du kan faktisk bruke noe navn i stedet for "selv" for dine metoder. - Metodene her ville fungere like bra hvis vi omdøpte variabelen «selv» til noe ord. Å bruke navnet "selv" er bare en konvensjon som er nyttig for Python-programmerere fordi den gjør koden mye mer standard og lett å forstå, selv om den er skrevet av noen andre. Mitt råd vil være å holde fast ved konvensjonene.


Noen mer avanserte funksjoner

Nå som vi har gått over det grunnleggende, la oss se på noen mer avanserte funksjoner i klasser, og hvordan de kan bidra til å gjøre programmeringen enklere å strukturere.

Den neste tingen vi skal snakke om, er arv. Som navnet kan antydes, er arv prosessen med å lage en ny klasse basert på en overordnet klasse, og tillate den nye klassen å arve egenskapene til foreldreklassen. Den nye klassen kan ta alle metodene og variablene fra foreldreklassen (ofte kalt baseklassen).

Arv er prosessen med å lage en ny klasse basert på en foreldreklasse.

La oss utvide vårt kjæledyreksempel for å se hvordan dette kan være nyttig. Hvis vi bruker "kjæledyr" som vår foreldreklasse, kan vi lage en barneklasse som arvet fra kjæledyrklassen. Barneklassen kan være noe som "hund" eller "fisk" - noe som fortsatt er et "kjæledyr", men er mer spesifikt enn det. En hund er et kjæledyr, og gjør det samme som alle kjæledyr gjør - for eksempel det spiser og sover og har en alder og en rekke ben - men det gjør andre ting som er spesifikke for å være en hund, eller i det minste mer spesifikt enn å være et kjæledyr: hunder har pels, men ikke alle kjæledyr gjør det. En hund kan bjeffe eller hente en pinne, men ikke alle kjæledyr ville.

Komme tilbake til poenget, si at vi ønsket å lage en klasse i vårt program for å representere en hund. Vi kan bruke arv til å arve metodene og variablene som finnes i "kjæledyr", slik at hunden vår kan ha et "numberOf Legs" og muligheten til å "sove", i tillegg til alle de hundespesifikke tingene vi kan lagre eller gjøre.

Nå lurer du kanskje på hvorfor vi ikke legger disse metodene og variablene inn i hundeklassen og slipper av kjæledyrklassen helt? Vel, arv gir oss to forskjellige fordeler over denne tilnærmingen: En, hvis vi vil ha et objekt som er et kjæledyr, men ikke en hund - et generisk kjæledyr, hvis du vil - det kan vi fortsatt gjøre. To, kanskje senere vil vi legge til en annen type kjæledyr - kanskje en fisk. Vi kan få den andre klassen også å arve fra kjæledyr, og begge klassene kan dele alt i kjæledyr, men har samtidig egne mer spesifikke metoder og variabler som bare gjelder for den typen gjenstand.

Vi blir litt bøyet ned i teorien her, så la oss skrive noe for å gjøre det litt tydeligere. Først skal vi skrive en ny klasse, kalt "hund", men denne gangen, mellom klassenavnet og kolonet, skal vi sette noen parenteser, og i dem skal vi skrive navnet av klassen som vi vil arve fra, som om vi passerer denne nye klassen et argument, som om vi ville ha en funksjon.

Neste, la oss gi denne klassen en enkel metode for å demonstrere hvordan det fungerer. Jeg skal legge til en 'bark'metode som vil skrive ut' woof ':

 klassen kjæledyr: number_of_legs = 0 def søvn (selv): print "zzz" def count_legs (selv): print "Jeg har% s ben"% selv.number_of_legs klassebok (kjæledyr): def bark (selv): print "Woof" 

Så, la oss se hva som skjer hvis vi gjør en forekomst av denne klassen. Jeg skal ringe til vår nye hund 'doug' igjen. Nå, hvis vi ringer doug.bark ():

 klassen kjæledyr: number_of_legs = 0 def søvn (selv): print "zzz" def count_legs (selv): print "Jeg har% s ben"% selv.number_of_legs klassebok (kjæledyr): def bark (selv): print "Woof" doug = hund () doug.bark () 

Som forventet bøyer Doug. Det er flott, men vi har ikke sett noe nytt ennå - bare en klasse med en metode. Hva arv har gjort for oss, er imidlertid å gjøre alle kjæledyrsfunksjonene og variablene tilgjengelige for oss gjennom vårt "doug" -objekt, så hvis jeg gjør noe slikt:

 klassen kjæledyr: number_of_legs = 0 def søvn (selv): print "zzz" def count_legs (selv): print "Jeg har% s ben"% selv.number_of_legs klassebok (kjæledyr): def bark (selv): print "Woof" doug = hund () doug.sleep () 

Så vil søvnmetoden også utføres riktig. I virkeligheten tilhører vårt doug-objekt både "pet" og "hundeklassen". For å sikre at variablene gjør det samme som metodene, la oss prøve dette:

 klassen kjæledyr: number_of_legs = 0 def søvn (selv): print "zzz" def count_legs (selv): print "Jeg har% s ben"% selv.number_of_legs klassebok (kjæledyr): def bark (selv): print "Woof" doug = hund () doug.number_of_legs = 4 doug.count_legs () 

Du kan se at doug fungerer akkurat som før, og viser at våre variabler blir arvet. Vår nye barneklasse er rett og slett en spesialisert versjon av foreldre en, med litt ekstra funksjonalitet, men beholder all tidligere funksjonalitet.


Så der har du det, en rask introduksjon til objektorientert programmering. Hold deg oppdatert for neste avdrag i denne serien, der vi skal jobbe med Python på nettet!