Já, góðan daginn,
nú er komið að því að tala um klasa og hlutbundna forritun.
Og ég ætla í þessu myndbandi að fara svona yfir helstu grundvallaratriði og
svona þau hugtök sem við þurfum að hafa á taktinum þegar við erum að tala um klasa
og ég ætla bara að byrja strax hérna með því að forritunarumhverfiið og búa til klasa svona tiltölulega einfaldan klasa sem þó gefur okkur
svona tækifæri til að ræða eins, þau svona helstu hugtök sem við þurfum að þekkja
og þessi klasi hann heitir counter.
Og hann hefur það hlutverk að halda utan um einhvern tiltekinn fjölda
og í Python, þá notar maður lykilorð sem heitir class þegar maður er að skilgreina klasa og það er venja að nota stóra stafi nöfnum á á það er að segja byrja nafn klasa með stórum staf í Python.
Og
Þannig að það sem ég er búinn að gera núna er ég búinn að lýsa því yfir að ég sé hérna með klasa sem heitir counter. Í augnablikinu hefur hann engin, engar aðgerðir og engin gögn. En það er eitthvað sem ég ætla að fylla inn smám saman.
Og það allra fyrsta sem maður gerir þegar maður býr sér til klasa
Það er nánast alltaf að búa til svo kallaða init fall og ef ég bara skrifa það upp þá hefur það þennan sérstaka rithátt að vera með tvö undirstrik á undan init og svo tvö undirstrik á eftir init.
Þetta er fall
og þetta fall hefur það hlutverk
að upphafs stilla gefi einhverja upphafs vinnslu
fyrir viðkomandi
klasa þegar tilvik af klasanum er búið til
og við eigum svo sem hægt er að ræða hér aðeins hvað hvað ég á við með tilvik. En þetta er
aðgerð sem verður kallað á þegar nýtt tilvik er smíðað
og fyrst ég er að tala um nýtt tilvik smíðað og kannski bara best að
setja það strax hérna inn
en gerum ráð fyrir að aðalforriti bíði, byrji hér.
Hvernig myndi ég búa til nýtt tilvik af counter? Jú, ég get einfaldlega sagt köllum hann counter eitt hérna.
Hann verður niðurstaðan af því að kalla á counter smiðinn.
Þetta er,
ég hef nafnið á klasanum í og svo svigi opnast, svigi lokast. Þá gefur það til kynna að ég sé að kalla hérna á eitthvað fall og það er það sem er raunverulega að gerast hér ef ég er að kalla á svokallaðan smið eða constructor
sem að
í því ferli verður síðan kallað á init fallið sem sér um að upphaf stilla.
Og þetta er í sjálfu sér ritháttur sem við höfum séð áður. Til dæmis ef ég væri með lista þá gæti ég sagt: a list er sama sem list svigi opnast, svigi lokast. Hérna er ég að kalla á listasmiðinn en það vill svo til að list er innbyggður klasi í Python.
En nú er ég sem sagt að búa mér til eigin klasa. Við getum sagt eigið tag sem heitir counter og ég kalla á smiðinn og í því ferli verður kallað á þetta init fall sem sér um einhvers konar upphafsstillingu.
Nú þetta init fall þarf að taka,
ja þarf í sjálfu sér ekki að taka
endilega viðföng en það tekur að minnsta kosti tilvísun á self.
Og
self er raunverulega tilvísun á hlutinn sjálfan.
Það er að segja, self hér
er tilvik af counter þannig að hér er counter einn raunverulega
tilvísun á þetta þennan hlut sem við vísum í hérna með self. Þetta kannski skýrist aðeins betur á eftir líka.
Ég ætla að hafa hérna
eina breytu sem er valkvæð sem ætla að kalla þetta value, og hún er hefur sjálfgefna gildið núll þannig segja það er að segja þegar ég bý mér til counter.
Þá ætla ég að hafa hann
með sjálfgefið gildi núll, en ég gæti sett inn eitthvert gildi sjálfur,
ef ég vil ekki hafa sjálfgefna gildið núll.
Og þessi counter hann á að eiga sér
breytu sem ég ætlaði einmitt að kalla líka bara value og sú breyta fær gildið úr [HIK: paramettinu] parameternum sem er sendur inn. Þannig sjáið hérna muninn en hér er um að value sem kemur inn sem parameter.
En
breytan value sé hún tilheyrir self og hvað self? Það er tilvikið af
counter.
Þannig self value fær þetta gildi, value sem er parameterinn.
Og þetta er það sem heitir tilvikabreyta instance variable.
Og við getum sagt þá kannski aðeins að nota þetta bara hjá okkur meðan við erum að ræða þessi hugtök að self punktur value
is an instance
variable eða tilvika breyta.
tilvika breyta
Ókei
í sjálfu sér þarf ég ekki meira til þess að
búa til tilvik af counter. Ég þarf ekki að forrita neitt meira, mig dugar að raunverulega hafa þetta init fall. Og
við skulum bara til að sannfæra okkur um það að ætla að keyra þetta hérna.
Þetta keyrir og gerir ekki neitt,
Ja, afhverju gerir það ekki neitt? Vegna þess að ég kalla og counter smiðinn hérna
sem býr til tilvikið og upphaf stillir það hérna með því að kalla á init. En ég er ekkert að prenta út hérna.
Hérna ætti kannski að segja
calling the constructor, smiðinn.
Constructor er smiður á íslensku,
nú ég talaði um að counter væri eitthvað sem ég gæti notað til að halda utan um einhver eitthvað, einhvern teljara og það er þannig að það er ekki mikið gagn í þessu ef við getum ekki hækkað teljarann og lækkað teljarann.
Þannig það sem ég mundi vilja geta gert hér er til dæmis það að eiga aðgerð sem heitir increment.
Og aðgerð segi ég: þetta er það sem heitir method á ensku
og aðgerðir er í sjálfu sér ekkert annað heldur en
fall.
Það heitir bara aðgerð þegar við erum að tala um klasa. Þannig method er raunverulega bara fall.
Og ég ætla að hafa, senda hérna inn
líka valkvætt value.
Og hvað gerir þetta? Því að hugmyndin með þessu er sú að ég geti hækkað teljarann um einn eða hugsanlega eitthvað meira en
það sem ég geri hér er segir bara: self value fæ [HIK: nújn] núna ég hækka það um value
þannig ef að
notandinn sem kallar á increment
tilgreini eitthvert gildi fyrir value þá verð ég að hækka það um það ef valið kemur ekki inn sem viðfang þá hækka um einn er það ekki af því að
sjálfgefna gildið er einn.
Þannig nú er ég kominn með aðra aðgerð heldur en init
aðgerðina
og þá ætti ég að geta notað hana hér og sagt: counter einn punktur
increment
svona.
Og þá kemur kannski spurning hér:
ja, ókei, bíðum aðeins spurningu, ég ætla að prófa þetta hérna sjá hvort þetta keyri,
já þetta keyri en þá sé ég ekki hver
niðurstaðan er vegna þess ég er ekki að prenta út hérna.
Og
við skulum prófa annað hérna.
Hvað gerist ef ég kalla núna með hérna? Sjáum við af value er default einn en ég gæti sent
svo inn eigum við að prófa það?
Þannig ég ætla að hækka um tvo í staðinn fyrir einn
og keyri og þetta gengur.
Sko það sem er maður þarf að átta sig á hér í upphafi er það að, og það er þetta kannski virðist vera dálítið skrýtið að þegar ég kalla fallið increment þá kalla ég á það með einu viðfangi hér í seinna skiptið og núll viðföngum hérna í upphafi.
En hérna stendur að það séu tvö viðföng self og value.
En
það þarf ekki að senda inn neina tilvísun á self vegna þess sem seld er hluturinn sjálfur. Það er að segja self er tilvísun í counter einn hérna,
þannig að við getum sagt hérna
counter einn is self in the call to increment.
Þannig að þetta self er raunverulega counter einn.
Value hins vegar er þessi tvistur hér eða ég sendi ekkert gildi inn fyrir value hérna upphaflega en þá var sjálfgefna gildið einn.
Nú það sem við vildum
náttúrulega geta gert er að prenta út. Hvernig lítur þetta increm, hvernig lýtur þetta counter object út?
Hvað gerist ef ég til dæmis bara reyni að prenta það hérna counter einn,
og keyra þetta svona?
Þá fæ ég er að counter er object, at einhverri minnis adressu. Þannig þetta hjálpar lítið til, ég, það sem ég sem ég mundi vilja sjá,
er hvert er innihald þessa hlutar eða þessa tilviks?
Og þá kemur til sögunnar fall sem maður nánast skrifar alltaf þegar maður er að búa til klasa,
og það er fallið s t r og aftur takið eftir, þá byrjaði það með tveimur undirstrikum og endar með tveimur undirstrikum. Það verður að heita hérna s t r
og það tekur einmitt self vegna þess að öll allar aðgerðirnar í klössun klössunum taka fyrsta viðfang sem self og tilgangur þessa falls er að skila af sér streng sem að stendur fyrir hlutinn sjálfan og ég ræð því alveg sjálfur sem forritari hverju ég skila hérna.
En í þessu tilviki væri eðlilegt fyrir mig að skila til dæmis hvert er gildið á tilvikinu? Það að segja þessi breyta self punktur value hérna.
Þannig að þetta fall á alltaf að skila streng þannig að við skulum skila hérna streng og segja bara:
counter value tvípunktur notum svo hérna
place holder.
Og nú er ég kominn format streng og formatera þetta með því að senda inn self value.
Þannig að self punktur value verður skipt út fyrir þennan place holder. Þannig nú er ég að skila strengur s t r.
Sjáum hverju þetta skilar
og þá fæ ég hérna counter value er þrír. Hvað gerðist hérna?
Þegar ég kalla hér á print
fyrir counter einn. Þá sér Python það að í fyrsta lagi er counter einn er tilvik af klasanum counter og athugar hvort það sé til s t r fall í þessum klasa og í þessu tilviki er það að ég er búinn að forrita s t r fall. Og þá verður kallað á það
og því skilað sem að fallið skilar.
Þannig tókuð eftir þegar s t r fallið var ekki til
þá fengum við eitthvað svona, counter object at einhverri minnis adressu. En um leið og ég var búinn að forrita fallið s t r
þá skilaðist hérna counter value er þrír. Og af hverju var það þrír? Vegna þess að ég var búinn að incremente-a einu sinni og svo raunverulega increment-a aftur en biðja um að increment-ið yrði
ef ég myndi bæta tveimur við gildið þannig þess að hann fékk þrjá.
Og það sem að við getum þá kannski talað um á þessum tímapunkti er það að
aðeins að ræða hérna þennan klasa counter. Sko counter er núna orðin hjúpun á ákveðna virkni er það ekki og raunverulega má segja hjúpun á ákveðnum gögnum og ákveðinni virkni.
Og það er akkúrat það sem klasar gera og tilgangur klasa er, að hjúpa inni í klasa, bæði gögn og aðgerðir.
Og hvaða gögn erum við með? Ja, klasinn á sér
breytuna value
það er eina breytan sem hann á raunverulega. Þetta er tilvika breytan value og það eru raunverulega gögnin í klasanum.
Hvaða aðgerðir eru í klasanum? Ja, það er í fyrsta lagi init aðgerðin sem sé um upphafsstillingu, það er s t r aðgerðin sem sér um að skila af sér
streng sem að einhverju leyti endurspeglar stöðuna á tilvikinu.
Og það er fallið increment
sem að gefur notandanum kleift að hækka teljarann.
Þannig það er mikilvægt að átta sig á því að
klasi er sem sagt hjúpun eða incapsulation á bæði gögnum og virkni.
Og
takið líka eftir því að ég sem notandi hérna í aðalforritinu ég þarf ekki að vita hvernig einstakar aðgerðir
eru útfærðar í counter. Ég þarf bara að vita hvernig ég á notaði, ég þarf bara að vita það er ákveðið
fall sem heitir increment sem ég get notað. Ég þarf ekki að vita hvað hvers konar gögn eru inni í þessu
þessum hlut, ég þarf ekki að vita hvernig einstök falleg aðgerðir eru útfærð.
Hérna væri nú
kannski gott að eiga líka aðra aðgerð sem heitir decrement er það ekki
decrement, sem gerir mér kleift að
minnka teljarann
og ég ætla að hafa bara sama valkvætt gildi sem á að minnka, sem á að minnka um.
Þannig að hérna síðan get ég sett self value er þá mínus samasem þetta gildi.
Og til að prófa þetta þá gæti ég sagt hérna: ja, prófum að kalla hér á decrement.
Bara svona þannig það ætti að minnka um einn.
Keyri þetta og nú fæ ég counter value og tveir er það ekki vegna þess að það var þrír, ég minnka eða það eru þá tveir núna.
Eitt sem er gott líka að tala um að við erum að tala um þessi hugtök er það að
ég talaði um að notandinn þyrfti bara að vita hvaða aðgerðir eru þarna sem menn geta notað.
það er að segja hér er ég að nota increment og hérna er ég að nota decrement, hérna er ég að nota smiðinn. Og þetta eru það sem kallast interface,
eða skil.
Notandinn þarf bara að þekkja interface-ið eða skilin,
og þau felast raunverulega í því hvaða föll er um að ræða hérna.
Þannig að við gætum raunverulega sagt hérna,
interface
for class
is the set of methods
that it defines, er það ekki?
Þetta eru skilin sem að
klasinn býður upp á og ég til þess að ég geti notað klasann. Þá þarf ég raunverulega bara að þekkja interface-ið eða skilin. Ég þarf ekki að vita hvernig einstakar aðgerðir eru, eru útfærðar.
Nú eitt hérna sem ég minntist ekki á en er eitthvað sem við höfum verið að nota raunverulega í þessu námskeiði er hvernig við köllum á aðgerð sem tilheyrir einhverju tilviki og við gerum það með því að nota
punkt hérna og þetta í kennslubókinni er talað um dot notation. Þetta höfum við séð margoft í námskeiðinu eins og til dæmis þegar við höfum verið með lista
og við höfum gert eitthvað svona a list punktur append. Við segjum einmitt punktur append og
það í þessu samhengi sést að við erum raunverulega að kalla á aðgerðir sem til heyrir þessu tilviki hérna.
Þess vegna notum við dot notation.
Og sama
er þá að gerast hér þegar við segjum counter einn [HIK: punktu] punktur increment.
Að þá er ég að kalla á aðgerð sem tilheyrir þessu tilviki.
En tilvikið er hluti af klasa og aðgerðin er skilgreind inni klasann.
Sko þetta er öðruvísi það er munur á því að segja til dæmis þær innbyggt falli í Python sem heitir sum ég get kallað fallið sum til dæmis fyrir einhvern lista og sjáið, þá er ég kalla fall sem tilheyrir ekki einhverju tilteknu tilviki,
þá ég ekki að nota dot notation.
Þannig það er munur á þessu
og það er þess vegna er talað um að falla kall sem tilheyrir klasa eða tilviki er
er oft vísað í sem method, sem er raunverulega ekkert annað en fall en þetta hér þegar ég kalla á til dæmis fallið sum, þá erum við að tala um svona stand alone fall sem tilheyrir ekki ákveðnu tilviki.
Ágætt að gera sér grein fyrir þessu.
Eitt sem að
við getum nefnt hérna í viðbót er það að
þetta hér self punktur value, er svokölluð tilvika breyta.
Það er vegna þess að hún fylgir sérhverju tilviki. Sérhvert tilvik á sér afrit af þessari breytu.
Við sjáum það til dæmis ef við segjum hérna. Ég ætla að búa til annan counter, counter tveir hérna.
Og ég kalla á smiðinn bý til annan counter
og segjum að ég segi ég já, við skulum bara gera lykkju hérna for i in range
hvað, núll upp í fimm.
Og köllum á
counter tveir punktur increment hérna.
Í hvert sinn.
Prentum síðan út
counter tvo.
Keyrum þetta,
þá sjáum við að seinni teljarinn hann hefur gildið fimm. Það þýðir það,
að fyrri teljarinn sem hefur gildi tvo, hann á sér tilvikabreytuna value. Hún hefur einmitt gildið tveir en seinna tilvikið sem heitir counter tveir. Hann á sér líka
tilvikabreytuna
value en hún hefur annað gildi, hún hefur fimm er það ekki?
Þannig að sérhvert tilvik á sér sitt eigið, sína eigin breytur.
Og þetta heita sem sagt instance variables.
Það er reyndar til annað sem heitir class variable.
Sem við getum aðeins skoðað hérna.
Og þá er það eitthvað sem er skilgreint
í klasanum
og tilheyrir ekki einstöku tilviki
heldur er sameiginleg breyta öllum tilvikum, getum við sagt. Ég gæti sagt hérna,
segjum ég vildi halda utan um fjölda af counter-um sem eru yfir höfuð búnir til,
þá gæti ég sagt hérna: já, ókei eigum okkur eitthvað sem heitir the number of instances,
látum það hafa gildið núll. Og í sérhvert sem að nýtt tilvik verður smíðað, nýtt tilvik af counter,
instance of counter. Þá ætla ég að hækka
þessar breytu.
Og þá ætla ég að vísa í hana sem counter punktur num instances
plús sama sem einn.
Þannig í sérhvert sinn sem kallað verður á init,
þá hækka ég einhverjar breytu sem heitir num instances en sú breyta tilheyrir kantar klasanum og hún er ekki sérstök fyrir
tilvikið sjálft vegna þess að ef svo væri mundi ég nota self fyrir hana að nota í klasa nafnið.
Skulum sjá keyrir þetta yfir höfuð?
Já, en hvernig get ég séð
hvaða gildi þessi breyta hefur sem er sem sagt klasa breyta eða class variable.
Jú, ég gæti bara prófað að prenta til dæmis eftir ég er búinn að búa til eitt tilvik af counter.
Getum við ekki bara prentað út hér?
Counter punktur num instances. Þannig ég vísa beint í klasa breytuna í counter.
Prentum það út.
Sjáið þá fékk ég eitt hérna vegna þess ég var búin að búa til eitt tilvik af counter
og
við getum þá gert það aftur eftir að ég bý til seinna tilvikið af counter þá ætti ég að fá tvo.
Já, þarna er þessi munur
á
tilvika breytu sem að vísar í með self og
klasa breytu sem að vísar í með nafninu á klasanum.
Já kannski að lokum að nefna það að
þegar við erum að búa til klasa eins og counter,
þá erum við í mörgum tilvikum í ákveðnu hlutverki sem svona
hönnuðir á klösum. Við erum að búa til að hjúpa ákveðna virkni,
búa til klasa,
þar sem við hjúpum ákveðna virkni sem er eins og við töluðum um að áður en það eru gögn og aðgerðir sem við hjúpum og við erum að búa til þessa klasa fyrir aðra forritara til að nota.
Og það sjáum við til dæmis í þessu aðalforriti hér,
að
ég er, gæti það gæti verið einn forritari sem býr til þennan klasa counter og hann yrði geymdur í einhverju skrá sem heitir counter punktur p y. Svo gæti
annar forritari import-að þá skrá
og nýtt sér þennan counter með því að búa til tilvik af honum
og nýtt sér raunverulega skilin interface-ið. Og aftur sem ég er alltaf að ítreka að
sá forritari sem eru að nota counter hann þarf ekkert að vita um hvernig viðkomandi hlutur er útfærður,
hann þarf bara að vita
hvaða aðgerðir er um að ræða. Menn þekkja skilin til að nota, geta nýtt sér og notað hlutinn.
Bara aðeins til að klára þetta vegna þess að ég var búin að setja einhverjar athugasemdir sem eru svona skýringar,
það sé alveg á hreinu hér að num instances
is a class variable.
Það er þessi munur, instance variable versus class variable.