1. díl - Úvod do objektově orientovaného programování v Pythonu

Python Objektově orientované programování Úvod do objektově orientovaného programování v Pythonu

Vítejte u prvního dílu úvodu do objektově orientovaného programování v Pythonu. Sekci Základní konstrukce v Pythonu již máme zasebou, minule jsme ji dokončili dílem Knihovny math a random . V této sekci se naučíme objektově programovat a hlavně objektově myslet. Je to něco trochu jiného, než jsme dělali doteď a samotný program už nebudeme chápat jako několik řádků příkazů, které interpret vykonává odshora dolů.

Objektově orientované programování (dále jen OOP) nevzniklo náhodou, ale je důsledkem vývoje, který k němu směřoval. Jedná se o moderní metodiku vývoje softwaru, kterou podporuje většina programovacích jazyků. Častou chybou je, že se lidé domnívají, že OOP se využívá pouze při psaní určitého druhu programů a jinak je na škodu. Opak je pravdou - OOP je filosofie, je to nový pohled na funkci programu a komunikaci mezi jeho jednotlivými částmi. Mělo by se používat vždy, ať už děláme malou utilitku nebo složitý databázový systém. OOP není jen technika nebo nějaká doporučená struktura programu, je to hlavně nový způsob myšlení, nový náhled na problémy a nová éra ve vývoji softwaru.

Nejprve se podíváme do historie, jak se programovalo dříve a které konkrétní problémy OOP řeší. Je to totiž důležité k tomu, abychom pochopili, proč OOP vzniklo.

Evoluce metodik

Mezi tím, jak se programovalo před 40ti lety a jak se programuje dnes, je velký rozdíl. První počítače neoplývaly velkým výkonem a i jejich software nebyl nijak složitý. Vývoj hardwaru je však natolik rychlý, že se počet tranzistorů v mikroprocesorech každý rok zdvojnásobí (Moorův zákon). Bohužel, lidé se nedokáží rozvíjet tak rychle, jako se rozvíjí hardware. Stále rychlejší počítače vyžadují stále složitější a složitější software (resp. lidé toho chtějí po počítačích stále více a více). Když se v jedné chvíli zjistilo, že okolo 90% softwaru je vytvořeno se zpožděním, s dodatečnými náklady nebo selhalo úplně, hledaly se nové cesty, jak programy psát. Vystřídalo se tak několik přístupů, přesněji se jim říká paradigma (chápejte jako směr myšlení). My si je zde popíšeme.

1. Strojový kód

Program byl jen souborem instrukcí, kde jsme neměli žádnou možnost pojmenovávat proměnné nebo zadávat matematické výrazy. Zdrojový kód byl samozřejmě specifický pro daný hardware (procesor). Toto paradigma bylo brzy nahrazeno.

2. Nestrukturované paradigma

Nestrukturovaný přístup je podobný assemblerům, jedná se o soubor instrukcí, který se vykonává odshora dolů. Zdrojový kód již nebyl závislý na hardwaru a byl lépe čitelný pro člověka, přístup na nějakou dobu umožnil vytvářet komplexnější programy. Bylo tu však stále mnoho úskalí: Jediná možnost, jak udělat něco vícekrát nebo jak se v kódu větvit, byl příkaz GOTO. GOTO nám umožňuje "skákat" na jednotlivá místa v programu. Místa byla dříve specifikována číslem řádku zdrojového kódu, což je samozřejmě nepraktické. Když do kódu vložíme nový řádek, čísla přestanou souhlasit a celý kód je rozbitý. Později vznikla možnost definovat tzv. "návěstí". Takto se obcházela např. absence cyklů. Takovýto způsob psaní programů je samozřejmě velice nepřehledný a brzy přestal postačovat pro vývoj složitějších programů.

Uvědomme si, že obrovské rozšíření počítačů za posledních několik dekád má na svědomí růst poptávky po softwaru a logicky také růst poptávky po programátorech. Jistě existují lidé, kteří dokáží bez chyby psát programy v ASM nebo jiných nízkých jazycích, ale kolik jich je? A kolik si asi za takovou nadlidskou práci účtují? Je potřeba psát programy tak, aby i méně zkušení programátoři dokázali psát kvalitní programy a nepotřebovali k tvorbě jednoduché utilitky 5 let praxe.

3. Strukturované programování

Strukturované programování je první paradigma, které se udrželo delší dobu a opravdu chvíli postačovalo pro vývoj nových programů. Programujeme pomocí cyklů a větvení. To je v podstatě to, kam jsme se doteď dostali.

Program lze rozložit do funkcí, jak jsme si již ukázali v díle Funkce a výjimky v Pythonu . U strukturovaného programování hovoříme o tzv. funkcionální dekompozici. Problém se rozloží na několik podproblémů a každý podproblém potom řeší určitá funkce s parametry. Nevýhodou je, že funkce umí jen jednu činnost, když chceme něco jiného, musíme napsat novou. Neexistuje totiž způsob, jak vzít starý kód a jen trochu ho modifikovat, musíme psát znovu a znovu - vznikají zbytečné náklady a chyby. Tuto nevýhodu lze částečně obejít pomocí parametrizace funkcí (počet parametrů poté ale rychle narůstá) nebo použitím globálních proměnných. S globálními daty vzniká však nové nebezpečí - funkce mají přístup k datům ostatních. To je začátek konce, nikdy totiž neuhlídáme, aby někde nedošlo k přepsání globálních dat mezi funkcemi a začne docházet k nekontrolovatelným problémům. Celý program se potom skládá z nezapouzdřených bloků kódu a špatně se udržuje. Každá úprava programu zvyšuje složitost, program potom nutně dojde do stavu, kdy náklady na přidávání nových funkcí vzrostou na tolik, že se program již nevyplatí rozšiřovat. Zástupci tohoto přístupu jsou například jazyky C a Pascal.

Mezi strukturovaným programováním a objektově orientovaným programováním existoval ještě mezičlánek, tzv. modulární programování, která nám umožňuje zapouzdřit určitou funkcionalitu do modulů. Stále však neexistuje způsob, jak již napsaný kód modifikovat a znovu využít.

Jak již jsem se zmínil na začátku článku, někdy se uvádí, že se jednoduché programy mají psát neobjektově, tedy strukturovaně. Není to však pravda. Když opomineme fakt, že porušujeme filozofii OOP jako takovou, nikdy nemůžeme vědět, zda se tento program neuchytí a z malé utilitky se nestane něco vážnějšího. Potom opět nutně dospějeme do stavu, kdy program nebude možné dál rozšiřovat a budeme ho buď muset zahodit nebo celý přepsat s pomocí OOP.

Neobjektovým metodám psaní kódu se přezdívá "spaghetti code", pro jejich nepřehlednost (protože špagety jsou zamotané).

Objektově orientovaný přístup

Jedná se o filozofii a způsob myšlení, designu a implementace, kde klademe důraz na znovupoužitel­nost. Přístup nalézá inspiraci v průmyslové revoluci - vynález základních komponent, které budeme dále využívat (např. když stavíme dům, nebudeme si pálit cihly a soustružit šroubky, prostě je již máme hotové).

Poskládání programu z komponent je výhodnější a levnější. Můžeme mu věřit, je otestovaný (o komponentách se ví, že fungují, jsou otestovány a udržovány). Pokud je někde chyba, stačí ji opravit na jednom místě. Jsme motivováni k psaní kódu přehledně a dobře, protože ho po nás používají druzí nebo my sami v dalších projektech (přiznejme si, že člověk je od přírody líný a kdyby nevěděl, že se jeho kód bude znovu využívat, nesnažil by se ho psát kvalitně :) ).

Znalosti, které jsme se doteď naučili, samozřejmě budeme používat dál. Náš kód budeme pouze jinak strukturovat a to do komunikujících objektů.

Jak OOP funguje

Snažíme se nasimulovat realitu tak, jak ji jsme zvyklí vnímat. Můžeme tedy říci, že se odpoutáváme od toho, jak program vidí počítač (stroj) a píšeme program spíše z pohledu programátora (člověka). Jako jsme tehdy nahradili assembler lidsky čitelnými matematickými zápisy, nyní jdeme ještě dál a nahradíme i ty. Jde tedy o určitou úroveň abstrakce nad programem. To má značné výhody už jen v tom, že je to pro nás přirozenější a přehlednější.

Základní jednotkou je objekt, který odpovídá nějakému objektu z reálného světa (např. objekt člověk nebo databáze).

Objekty v objektově orientovaném programování

Objekt má své atributy a metody.

Atributy Atributy objektu jsou vlastnosti neboli data, která uchovává (např. u člověka jméno a věk, u databáze heslo). Jedná se o prosté proměnné, se kterými jsme již stokrát pracovali. Někdy o nich hovoříme jako o vnitřním stavu objektu.

Slovo vlastnost si v Microsoftu vyhradili pro specifické využití a to samé platí pro atribut. Proměnným objektů říkají field, což se zase kryje s českým slovem pole. Budu tedy používat slovo atribut, i když to nebude úplně korektní.

Metody Metody jsou schopnostmi, které umí objekt vykonávat. U člověka by to mohly být metody: jdi_do_prace(), pozdrav() nebo mrkni(). U databáze pridej_zaznam() nebo vyhledej()). Metody mohou mít parametry a mohou také vracet nějakou hodnotu. Velmi dobře je známe, používali jsme např. metodu upper() na objektu string (řetězec). Řetězec je vlastně objekt, který reprezentuje v realitě nějaký text. Vidíte, že si můžeme jednoduše představit, že jednáme s řetězcem textu, něco mu přikazovat nebo na něm něco nastavovat. Obsahuje metody, které řetězec umí vykonávat (nahrazování jeho částí, převádění na velká písmena apod.).

Objekty v objektově orientovaném programování

Ve starších jazycích metody nepatřily objektům, ale volně se nacházely v modulech. Místo text.upper() bychom tedy postaru psali upper(text). Nevýhodou je samozřejmě zejména to, že metoda upper zde nikam nepatří. Není způsob, jakým si vyvolat seznam toho, co se s řetězcem dá dělat a v kódu je nepořádek. Navíc nemůžeme mít 2 metody se stejným názvem, v OOP můžeme mít uzivatel.vymaz() a clanek.vymaz(). To je velmi přehledné a jednoduché, ve strukturovaném programu bychom museli psát: vymaz_uzivate­le(uzivatel) a vymaz_clanek(cla­nek). Takovýchto hloupých metod bychom museli mít někde rozházených tisíce. Pokud vám to připomíná jazyk PHP, bohužel máte pravdu. PHP je v tomto opravdu hrozné a to z toho důvodu, že jeho návrh je starý. Sice se časem plně přeorientovalo na objekty, ale jeho základy se již nezmění. Python je naštěstí jazyk moderní a plně podporuje objektově orientované paradigma.

V několika následujících článcích si vysvětlíme jen úplné základy, tedy jak objekty vytvářet a jak zapouzdřit jejich vnitřní logiku. Dalším funkcím OOP (mluvím zejména o dědičnosti) bude věnován až pozdější díl, aby toho nebylo najednou moc :)

Třída

S pojmem třída jsme se již také setkali, chápali jsme ji jako soubor příkazů. Třída však umožňuje mnohem více. Třída je vzor, podle kterého se objekty vytváří. Definuje jejich vlastnosti a schopnosti.

Objekt, který se vytvoří podle třídy, se nazývá instance. Instance mají stejné rozhraní jako třída, podle které se vytváří, ale navzájem se liší svými daty (atributy). Mějme například třídu Člověk a od ní si vytvořme instance karel a josef. Obě instance mají jistě ty samé metody a atributy, jako třída (např. jméno a věk) a metody (jdi_do_prace() a pozdrav()), ale hodnoty v nich se liší (první instance má v atributu jméno hodnotu "Karel" a ve věk 22, druhá "Josef" a 45).

Objekty v objektově orientovaném programování

Komunikace mezi objekty probíhá pomocí předávání zpráv, díky čemuž je syntaxe přehledná. Zpráva obvykle vypadá takto: příjemce.jméno_me­tody(parametry). Např. karel.pozdrav(sou­sedka) by mohl způsobit, že instance karel pozdraví instanci sousedka.

OOP stojí na základních třech pilířích: Zapouzdření, Dědičnost a Polymorfismus. Vysvětleme si první z nich:

Zapouzdření

Zapouzdření umožňuje skrýt některé metody a atributy tak, aby zůstaly použitelné jen pro třídu zevnitř. Objekt si můžeme představit jako černou skřínku (anglicky blackbox), která má určité rozhraní (interface), přes které jí předáváme instrukce/data a ona je zpracovává. Nevíme, jak to uvnitř funguje, ale víme, jak se navenek chová a používá. Nemůžeme tedy způsobit nějakou chybu, protože využíváme a vidíme jen to, co tvůrce třídy zpřístupnil.

Příkladem může být třída člověk, která bude mít atribut datum_narozeni a na jeho základě další atributy: plnolety a vek. Kdyby někdo objektu zvenčí změnil datum_narozeni, přestaly by platit proměnné plnolety a vek. Říkáme, že vnitřní stav objektu by byl nekonzistentní. Toto se nám ve strukturovaném programování může klidně stát. V OOP však objekt zapouzdříme a atribut datum_narozeni označíme jako privátní, zvenčí tedy nebude viditelný. Naopak ven vystavíme metodu zmen_datum_na­rozeni(), která dosadí nové datum narození do proměnné datum_narozeni a zároveň provede potřebný přepočet věku a přehodnocení plnoletosti. Použití objektu je bezpečné a aplikace stabilní.

Zapouzdření tedy donutí programátory používat objekt jen tím správným způsobem. Rozhraní (interface) třídy rozdělí na veřejně přístupné a její vnitřní strukturu.

Příště si vytvoříme svůj první objektový program.


 

  Aktivity (1)

Článek pro vás napsal gcx11
Avatar
(^_^)

Jak se ti líbí článek?
Celkem (10 hlasů) :
4.94.94.94.94.9


 



 

 

Komentáře

Avatar
Denis Homolík (Alfonz):

Nebylo by lepší udělat sekci OOP než opakovat to stejné v každé sekci?Přece i smysl OOP je aby se nic zbytečně neopakovalo :) . Přece je to jen teorie.

Odpovědět 8.6.2014 20:50
Vše je možné, dokud si to myslíte!
Avatar
gcx11
Redaktor
Avatar
Odpovídá na Denis Homolík (Alfonz)
gcx11:

Je to součást seriálu. Navíc Python má trochu jinou syntaxi a navíc zde máš odkazy na další témata - např. funkce, které se ti budou jistě v dalších dílech hodit.

 
Odpovědět 8.6.2014 21:00
Avatar
Odpovídá na gcx11
Denis Homolík (Alfonz):

Myslím, že bez odkazů by se to obešlo. Ale jinak je to zkopírované z ostatních seriálů. Vždyť je to přece proti logice OOP - spát stále to samé. To že má jinou syntaxi je přece jedno. Sekce by obsahovala pouze pár seriálů kde není potřeba jazyk.

Odpovědět 8.6.2014 22:56
Vše je možné, dokud si to myslíte!
Avatar
David Čápka
Tým ITnetwork
Avatar
Odpovídá na Denis Homolík (Alfonz)
David Čápka:

Denisi, když si koupíš knihu, taky tě odkazuje na jiné knihy, kde je něco, co už třeba někdo napsal? Čtenář si chce přečíst seriál od začátku do konce a tak, aby říkal přesně to, co platí pro ten jeden daný jazyk, který se učí. Všimni si, že se ty články liší, minimálně konvencemi v pojmenování metod.

Odpovědět  +4 9.6.2014 10:17
Miluji svou práci a zdejší komunitu, baví mě se rozvíjet, děkuji každému členovi za to, že zde působí.
Avatar
hanpari
Redaktor
Avatar
hanpari:

Myslím, že trochu pravdy máte všichni. Je to opakování téhož, na druhou stranu každá IT kniha obsahuje menší nebo větší úvod do celé problematiky, takže se Gcx11 držel běžného postupu.
Mne třeba zarazila ta věta o plné podpoře objektového paradigmatu v pythonu. Já třeba s tímhle problémy, protože když jsem čekal podobný zápis a podobné vlastnosti jako u csharp, python mne vždycky překvapil. Možná bych tedy spíš zdůraznil to, v čem se python liší a také proč.
Typický příklad jsou třeba privátní členy objektů, které v pythonu sice v jakési formě existují, ale obecně se nedoporučují používat - a ostřílený pythonýři razí heslo: "Všichni jsme dospělí a víme, co děláme."

 
Odpovědět  +1 10.6.2014 5:41
Avatar
Odpovídá na Denis Homolík (Alfonz)
Michal Žůrek (misaz):

Popis teorie je jen začátek, jak se to rozjede jsou někde i dost velké odlišnosti.

Odpovědět 10.6.2014 6:46
Nesnáším {}, proto se jim vyhýbám.
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 6 zpráv z 6.