Python from Scratch programare orientată pe obiecte

Bine ați venit înapoi la lecția a patra în cadrul nostru Python de la Scratch serie. Acest tutorial va presupune cunoștințe anterioare despre variabile, tipuri de date, funcții și rezultate de tipărire. Dacă nu sunteți la curent, consultați cele trei articole din seria anterioare, pentru a vă recupera.

Astăzi, vom fi încurcați în subiectul programării orientate pe obiecte (OOP). OOP este o modalitate foarte puternică de organizare a codului dvs. și înțelegerea solidă a conceptelor din spatele acestuia vă poate ajuta într-adevăr să obțineți maximum de codificare.


Preferați un scenariu?


Transcriere


Ce este programarea orientată pe obiecte?

Python este conceput în primul rând ca un limbaj de programare orientat pe obiecte - dar ceea ce înseamnă "obiect orientat" înseamnă de fapt?

Există o varietate de definiții ale termenului și ați putea vorbi literalmente ore în încercarea de a explica intuițiile complicate, nuanțele și diferențele în implementări, dar voi încerca să ofere o prezentare generală rapidă.

În general, programarea orientată pe obiecte este conceptul care, în programare, obiectele pe care le manipulăm sunt mai importante decât logica necesară manipulării acestor obiecte. În mod tradițional, un program a fost văzut ca o rețetă - un set de instrucțiuni pe care le urmați de la început până la sfârșit pentru a finaliza o sarcină. Acest lucru poate fi în continuare adevărat, iar pentru multe programe simple, este tot ceea ce este necesar. Această abordare este uneori cunoscută ca programare procedurală.

PLO pune obiecte în centrul procesului.

Pe de altă parte, pe măsură ce programele devin tot mai complexe și mai complicate, logica necesară pentru a le scrie într-un mod pur procedural devine din ce în ce mai răsturnată și greu de înțeles. Adesea, abordările orientate spre obiect pot ajuta în acest sens.

Când vorbim despre abordări orientate pe obiecte, ceea ce facem este să punem obiectele în centrul procesului, în loc să le folosim pur și simplu ca containere necesare pentru informare ca parte a instrucțiunilor noastre procedurale. În primul rând, definim obiectele pe care vrem să le manipulăm și modul în care acestea se raportează unul la celălalt, și apoi începem să-l caram cu logică pentru a face programul să funcționeze.

Când vorbesc despre "obiecte", pot vorbi despre tot felul de lucruri. Un "obiect" poate reprezenta o persoană (definită de proprietăți cum ar fi numele, vârsta, adresa etc.) sau o companie (așa cum este definită de lucruri precum numărul de angajați etc.) sau chiar ceva mult mai abstract buton în interfața computerului.

În această introducere, nu vom acoperi toate conceptele din acest subiect pentru că am fi aici toată noaptea, dar până la sfârșitul tutorialului, sper că veți avea o înțelegere solidă a principiilor de care aveți nevoie pentru a începe imediat folosind câteva tehnici simple orientate spre obiect în programele dvs. Python. Chiar mai bine, aceste concepte sunt destul de asemănătoare într-o mulțime de medii de programare. Transferul cunoștințelor de la limbă la limbă este destul de frumos.


Noțiuni de bază

Am menționat mai devreme că primul lucru pe care ar trebui să-l facem atunci când mergem pentru o abordare OOP este să definim obiectele pe care le vom folosi. Modul în care facem acest lucru este să definim mai întâi proprietățile pe care le posedă folosind o clasă. Vă puteți gândi la o clasă ca la un fel de șablon; un ghid pentru modul în care un obiect ar trebui structurat. Fiecare obiect aparține unei clase și moștenește proprietățile acelei clase, dar acționează în mod individual asupra celorlalte obiecte ale acelei clase.

Un obiect este uneori denumit "instanță" a unei clase.

Ca un exemplu simplu, ați putea avea o clasă numită "persoană" cu, de exemplu, o vârstă și o proprietate de nume, iar o instanță a acelei clase (un obiect) ar fi o singură persoană. Acea persoană ar putea avea un nume? Andy? și o vârstă de 23 de ani, dar ați putea avea simultan o altă persoană aparținând aceleiași clase cu numele de "Lucy"? și o vârstă de 18 ani.

Este greu de înțeles acest lucru fără a fi văzut în practică, așa că hai să facem un cod real.

Definirea unei clase

Pentru a defini o clasă, în mod tipic tipic Python, vom folosi cuvântul "clasă", urmat de numele noii clase. Voi face o clasă nouă aici, numită "animal de casă". Utilizăm un nume după nume și apoi orice element conținut în definiția clasei este indentat. Cu toate acestea, cu o clasă, nu există paranteze:

 animal de companie clasa: 

Deci acum avem o clasă, dar este mai degrabă inutilă fără nimic în ea. Pentru a începe, să-i dăm câteva proprietăți. Pentru a face acest lucru, pur și simplu definiți câteva variabile în interiorul clasei - voi merge cu numărul de picioare pentru a începe. Ca de obicei, ar trebui să denumiți întotdeauna variabilele dvs. astfel încât să fie ușor de spus ce sunt. Să fim originale și să le numim 'number_of_legs'. Trebuie să definim o valoare sau vom primi o eroare. Voi folosi 0 aici (nu contează prea mult în acest caz, deoarece numărul de picioare va fi specific fiecărui exemplu al clasei - un pește nu are aceleași cantități de picioare ca un câine sau o rață, etc - deci va trebui să schimbăm acea valoare pentru fiecare obiect oricum).

 animal de companie de clasă: number_of_legs = 0 

Instanțe și variabile membre

O clasă pe cont propriu nu este ceva pe care să-l puteți manipula direct; în primul rând, trebuie să creăm o instanță a clasei cu care să se joace. Putem stoca acea instanță într-o variabilă. În afara clasei (fără nicio indentare), să facem o instanță a clasei și să o stocăm în variabila "doug". Pentru a face o nouă instanță a unei clase, introduceți pur și simplu numele clasei și apoi o pereche de paranteze. În acest moment, nu este nevoie să vă faceți griji cu privire la paranteze, dar mai târziu veți vedea că sunt acolo deoarece, ca o funcție, există o modalitate de a trece într-o variabilă pentru a fi folosită de clasă atunci când creați pentru prima dată instanța.

O clasă pe cont propriu nu este ceva pe care îl puteți manipula direct.

 animal de companie clasa: number_of_legs = 0 doug = animal de companie () 

Acum, că avem o instanță a unei clase, cum accesăm și manipulăm proprietățile sale? Pentru a face referire la o proprietate a unui obiect, mai întâi trebuie să-i spunem Pythonului ce obiect (sau ce exemplu dintr-o clasă) vorbim, așa că vom începe cu "doug". Apoi, vom scrie o perioadă pentru a indica faptul că facem referire la ceva care este conținut în instanța noastră. După această perioadă, adăugăm numele variabilei noastre. Dacă accesăm number_of_legs variabilă, va arăta astfel:

 doug.number_of_legs 

Putem trata acest lucru exact așa cum am trata orice altă variabilă - aici o să presupun că doug este un câine și va da acelei variabile valoarea de 4.

Pentru a accesa această variabilă, o vom folosi din nou exact așa cum am trata orice altă variabilă, dar folosind asta doug.number_of_legs proprietății în loc de numele variabilei normale. Să punem o linie pentru a tipări câte picuri de picioare avem, astfel încât să putem arăta că funcționează așa cum ar trebui:

 animal de clasa: number_of_legs = 0 doug = animal de companie () doug.number_of_legs = 4 print "Doug are picioare% s." % doug.number_of_legs 

Dacă executați codul de mai sus, veți vedea că acesta este tipărit pentru noi. Acesta a definit clasa noastră de animale de companie, a creat o nouă instanță a acelei clase și a stocat-o în variabila "doug", iar apoi, în interiorul acelei instanțe, îi este atribuită valoarea 4 la number_of_legs variabilă pe care a moștenit-o din clasa sa.

Deci, puteți vedea din acest exemplu foarte simplificat cum puteți începe să construiți structuri de date modulare, clare și ușor de utilizat și puteți începe să scalați destul de frumos.


Introducerea logicii

Bine, deci sunt foarte elementele de bază ale clasei și obiectelor, dar în prezent nu putem decât să folosim într-adevăr clase ca structuri de date - sau, containere pentru variabile. Asta e bine și bine, dar dacă vrem să începem să îndeplinim sarcini mai complexe cu datele pe care le manipulăm, avem nevoie de o modalitate de a introduce o anumită logică în aceste obiecte. Modul în care facem acest lucru este cu metode.

Metodele, în esență, sunt funcții cuprinse într-o clasă. Definiți unul în exact același mod ca și cum ați fi o funcție, dar diferența este că o puneți într-o clasă și aparține acelei clase. Dacă doriți vreodată să apelați această metodă, trebuie să trimiteți mai întâi un obiect din acea clasă, la fel ca și variabilele la care ne-am uitat anterior.

Metodele, în esență, sunt funcții cuprinse într-o clasă.

Voi scrie un exemplu rapid aici în clasa pentru animale de companie pentru a demonstra; să creați o metodă, numită "somn", care va tipări un mesaj atunci când este inițial chemat. Ca o funcție, o să pun "def" pentru "define", iar apoi o să scriu numele metodei pe care doresc să o creez. Apoi ne vom pune parantezele și punct și virgulă și apoi vom începe o nouă linie. Ca de obicei, orice element inclus în această metodă va fi aliniat la un nivel suplimentar.

Acum, există o altă diferență între o metodă și o funcție: o metodă întotdeauna, întotdeauna, trebuie întotdeauna să aibă un argument, numit "sine" între paranteze. Atunci când Python numește o metodă, ceea ce face este să treacă obiectul curent la acea metodă ca primul argument. Cu alte cuvinte, când sunăm doug.sleep (), Python va trece de fapt obiectul "doug" ca argument pentru metoda somnului.

Vom vedea de ce mai târziu, dar pentru moment trebuie să știți că, cu ajutorul unei metode, întotdeauna trebuie să includeți mai întâi un argument numit "auto" în listă (dacă doriți să adăugați mai multe argumente, le puteți adăuga după aceea, exact dacă ați trece mai multe argumente la o funcție). Dacă nu includeți acest argument, când executați codul, veți avea o eroare aruncată deoarece Python trece într-un argument (acest obiect "de sine") și metoda spune: "Hei, omule, Nu iau argumente, despre ce vorbești? ". Este același lucru ca și cum ați încercat să transmiteți un argument într-o funcție care nu acceptă argumente.

Deci, iată ce avem până acum:

 animal de companie clasa: number_of_legs = 0 def sleep (self): doug = animal de companie () 

În cadrul acestei metode, vom scrie o declarație de tipărire după cum urmează:

 animale de companie clasa: number_of_legs = 0 def sleep (self): print "zzz" doug = animal de companie () 

Acum, dacă vrem să folosim această metodă, pur și simplu folosim o instanță a clasei pentru animalele de companie pentru ao face referire. La fel ca și number_of_legs variabila, scrieți numele instanței (avem unul numit doug), apoi o perioadă, apoi numele metodei care include paranteze. Rețineți că numim somn fără argumente, dar Python va adăuga în sine acel argument, așa că vom ajunge la un nivel corect de argumente în total.

 animal de companie clasa: number_of_legs = 0 def sleep (self): print "zzz" doug = animal () doug.sleep () 

Dacă executați acest cod, ar trebui să vedeți că acesta imprimă mesajul pe care l-am scris.

Date

Excelent, așa că acum scrieți o nouă metodă de a tipări câte picioare are animalul de companie, pentru a demonstra modul în care puteți folosi metode pentru a începe să manipulați datele din cadrul clasei și pentru a demonstra de ce trebuie să includem acest " argument. Să facem o nouă metodă, numită "count_legs'.

Aici intră argumentul "de sine". Amintiți-vă când accesăm number_of_legs din afara clasei și a trebuit să folosim "doug.number_of_legs" în loc de doar "number_of_legs"? Se aplică același principiu; dacă vrem să știm ce conține această variabilă, trebuie să o menționăm mai întâi specificând instanța care conține acea variabilă.

Cu toate acestea, nu știm ce va fi numit instanța atunci când vom scrie clasa, așa că vom ajunge în jurul valorii de folosind variabila "de sine". "auto" este doar o referință la obiectul care este în prezent manipulat. Deci, pentru a accesa o variabilă din clasa curentă, pur și simplu trebuie să o prefigurați cu "sine" și apoi o perioadă, cum ar fi:

 pentru animalele de companie de clasă: number_of_legs = 0 def sleep (self): print "zzz" def count_legs (self): print "Am picioare% s"% doug.number_of_legs = 4 doug.count_legs 

În practică, ceea ce înseamnă că ori de câte ori scrieți "sine" în metoda dvs., atunci când executați metoda pe care eu o înlocuim cu numele obiectului, atunci atunci când numim "doug.count_legs ()", "sinele" este înlocuit cu "doug". Pentru a demonstra cum funcționează acest lucru cu mai multe instanțe, să adăugăm oa doua instanță, reprezentând un alt animal, numit "nemo":

 animal de companie clasa: number_of_legs = 0 def sleep (self): print "zzz" def count_legs (self): print "Am picioare% s"% self.number_of_legs doug = = animal () nemo.number_of_legs = 0 nemo.count_legs () 

Acest lucru va imprima un mesaj pentru 4 și apoi 0 picioare, așa cum am dorit, deoarece atunci când numim "nemo.count_legs ()," eu "este înlocuit cu" nemo "în loc de" doug ".

În acest fel, metoda noastră se va executa exact așa cum se intenționează deoarece referința "de sine" se va modifica dinamic în funcție de context și ne va permite să manipulăm datele numai în cadrul obiectului curent.

Principalele lucruri pe care trebuie să le ții minte despre metode sunt că ele sunt exact ca și funcții, cu excepția faptului că primul argument trebuie să fie "de sine" și că pentru a face referire la o variabilă internă trebuie să prefaceți numele variabilei cu ".

La fel ca o notă: Puteți folosi de fapt orice nume în loc de "sine" pentru metodele tale. - Metodele de aici ar funcționa la fel de bine dacă am redenumit variabila "eu" la orice cuvânt. Folosirea numelui "self" este pur și simplu o convenție utilă programatorilor Python, deoarece face codul mult mai standard și ușor de înțeles, chiar dacă este scris de altcineva. Sfatul meu ar fi să rămânem la convenții.


Unele funcții mai avansate

Acum, că am trecut peste elementele de bază, să aruncăm o privire la unele caracteristici mai avansate ale clasei și cum pot ajuta la facilitarea structurării programării.

Următorul lucru despre care vom vorbi este moștenirea. După cum se poate numi și numele, moștenirea este procesul de a face o clasă nouă bazată pe o clasă parentală și care permite noii clase să moștenească caracteristicile clasei părinte. Noua clasă poate lua toate metodele și variabilele din clasa parentală (adesea numită clasa "de bază").

Moștenirea este procesul de a face o clasă nouă bazată pe o clasă părinte.

Să ne extindem exemplul de companie pentru a vedea cum ar putea fi util acest lucru. Dacă vom folosi "animalul de casă" ca clasă părinte, am putea crea o clasă de copii care a moștenit de la clasa pentru animale de companie. Clasa copil ar putea fi ceva de genul "câine" sau "pește" - ceva care este încă "animal de casă", dar este mai specific decât asta. Un câine este un animal de companie și face aceleași lucruri pe care le fac toate animalele de companie - de exemplu, mănâncă și doarme și are o vârstă și un număr de picioare - dar are și alte lucruri specifice pentru a fi un câine sau cel puțin specific decât a fi un animal de companie: câinii au blană, dar nu toate animalele de companie nu. Un câine ar putea lătrui sau să aducă un băț, dar nu toate animalele de companie ar fi.

Revenind la acest punct, spunem că am vrut să facem o clasă în programul nostru de a reprezenta un câine. Am putea folosi moștenirea pentru a moșteni metodele și variabilele conținute în "animalele de companie", astfel încât câinele nostru ar putea avea un "număr de picioare" și capacitatea de a "dormi", pe lângă toate lucrurile specifice câinilor pe care le putem stoca sau face.

Acum, s-ar putea să te întrebi de ce nu punem aceste metode și variabile în clasa câinilor și să scapi de clasa de animale de companie în întregime? Ei bine, moștenirea ne oferă două avantaje distincte față de această abordare: Unul, dacă vrem un obiect care este un animal de companie, dar nu este un câine - un animal de companie generic, dacă vreți - putem încă face acest lucru. Doi, poate mai târziu, dorim să adăugăm un al doilea tip de animal de companie - poate un pește. Putem face ca a doua clasă să moștenească de asemenea de la animalul de companie, astfel încât ambele clase să poată partaja totul cu animalele de companie, dar în același timp să aibă propriile metode și variabile specifice, care se aplică numai acelui tip de obiect.

Suntem puțin împușcați în teoria de aici, așa că să scriem ceva pentru a face ceva mai clar. În primul rând, vom scrie o nouă clasă, numită "câine", dar de data aceasta, între numele clasei și colon, vom pune niște paranteze, iar în ele vom scrie numele a clasei pe care dorim să o moștenim, ca și cum ar trece un nou argument în această clasă nouă, cum ar fi o funcție.

Apoi, să oferim acestei clase o metodă simplă pentru a demonstra cum funcționează. Voi adăuga un "latra"metoda care va imprima" woof ":

 animal de clasa: number_of_legs = 0 def sleep (self): print "zzz" def count_legs (self): print "Am picioare% s"% self.number_of_legs caini de clasa: 

Deci, acum să vedem ce se întâmplă dacă facem o instanță a acestei clase. O să-l sun din nou pe noul nostru câine. Acum, dacă sunăm doug.bark ():

 animal de clasa: number_of_legs = 0 def sleep (self): print "zzz" def count_legs (self): print "Am picioare% s"% self.number_of_legs caini de clasa: doug = câine () doug.bark () 

După cum era de așteptat Este minunat, dar nu am mai văzut nimic nou - doar o clasă cu o metodă. Ce moștenire a făcut pentru noi, totuși, este să facem toate funcțiile și variabilele de companie disponibile pentru noi prin obiectul nostru "doug", așa că dacă fac ceva de genul acesta:

 animal de clasa: number_of_legs = 0 def sleep (self): print "zzz" def count_legs (self): print "Am picioare% s"% self.number_of_legs caini de clasa: doug = câine () doug.sleep () 

Apoi metoda de somn va executa, de asemenea, corect. De fapt, obiectul nostru doug aparține atât clasei "PET" cât și clasei "câine". Pentru a se asigura că variabilele fac același lucru cu metodele, să încercăm:

 animal de clasa: number_of_legs = 0 def sleep (self): print "zzz" def count_legs (self): print "Am picioare% s"% self.number_of_legs caini de clasa: doug = câine () doug.number_of_legs = 4 doug.count_legs () 

Puteți observa că această acțiune acționează exact ca înainte, arătând că variabilele noastre sunt moștenite. Noua noastră clasă pentru copii este pur și simplu o versiune specializată a părintelui, cu unele funcționalități suplimentare, dar care păstrează toate funcționalitățile anterioare.


Deci, aveți o prezentare rapidă a programării orientate pe obiecte. Rămâi acordat pentru următoarea tranșă din această serie, unde vom lucra cu Python pe web!

Cod