Hodně teorie kolem pojmů, které se v objektově orientovaném programování používají - třída, instance, metoda plus jedna praktická ukázka. A na závěr samozřejmě úkol.
Pojmy, proměnné instance, self, dobrovolné argumenty metod
Pojmy
Je velká škoda, když člověk nepochopí OOP jen proto, že nerozumí všem těm hrozným cizím slovům, která se tu používají. Jako bych to slyšel: "To jsou furt nějaké třídy, instance, metody, atributy, k čertu s tím, já chci přece jen programovat!" Ta cizí slova jsou jen proto, abychom se domluvili, když si o tom budeme povídat, není to samoúčelné. Jinak bychom museli mluvit asi takto: "No tamto, jak je to po tom slovu class." Nebo: "Tamto, jako se to píše se závorkami a předtím je tečka a nefunguje to samo o sobě a je to hodně podobný jako funkce."
Proto shrnu objektové pojmosloví. Je třeba mu plně porozumět, anebo alespoň vědět, kde to najdu, když to budu potřebovat. Kdyby cokoliv z tohoto nebylo jasné, ptejte se v Poradně nebo zkuste jiný zdroj (knihu), kde vám bude výklad dávat větší smysl.
Třída
Třída (anglicky class) je vlastně takový kontejner, idea, prototyp konkrétní věci. Docela přirozeně se dá přirovnat ke třídám v přírodopise a biologii. Všechny opice mají určité společné znaky, které jsou právě zahrnuty ve třídě. Všechny konkrétní opičky, co kdy se narodily, měly všechno, co třída opiček obsahuje, jen tu společnou formu naplňují konkrétním obsahem. Každá opička má sice jiné jméno nebo hmotnost, ale každá má tu vlastnost, tu schopnost jméno či hmotnost vůbec mít.
Instance
Instance (anglicky instance) je pojmenování, zrod, vytvoření, narození konkrétní opičky. Nezaměňujte se jménem opičky. Jméno se opičce dává až po narození.
Příklad: mojeOpicka=Opicky() versus mojeOpicka.jmeno(u'Eliška')
Metoda
Metoda (anglicky method) je de facto to samé jako funkce, jen nesmí stát osamocena. Vždy patří k nějaké instanci, nějakému objektu, bez kterého nemá smysl. Je to jeden z hlavních rysů OOP.
Příklad: jmeno() existuje jen u instancí Opicky::
mojeOpicka=Opicky()
mojeOpicka.jmeno("Jiri") # spravne
jmeno() # chyba
Učíme opičku pamatovat si své jméno
Zatím umí naše opička jen jednu věc: umí říkat, že je instance. Tak jí naučíme říkat své jméno. Nejdříve ji ale musíme říci, jak se jmenuje. A úplně nejdříve to musíme naprogramovat ve třídě opiček.
Než začneme, je dobrým zvykem si rozmyslet, jak na to. Já bych navrhoval:
mojeOpicka.jmeno('Hopsanda') # řekneme jí jak se jmenuje
mojeOpicka.jmeno() # řekne nám, jak se jmenuje
Musím nejdříve vytvořit metodu jmeno(), která může (může, ale nemusí!) přijímat jeden argument. Podle toho, jestli argument v závorkách bude nebo nebude, podle toho musí metoda bud "číst" nebo "psát" (pamatovat si nebo mluvit). Začneme pamatováním si:
# -*- coding: utf-8 -*-
# Program Opičky - Úvod do OOP
class Opicky:
u"Počítačová opička"
def promluv(self):
print u"Ahoj, já jsem instance třídy Opicky!"
def jmeno(self, nazev):
self.nick=nazev
# ---- hlavni program ---------------------------
mojeOpicka=Opicky()
mojeOpicka.promluv()
mojeOpicka.jmeno('Johanka')
Vysvětlení
Přibyla nová metoda jmeno, která má dva argumenty: (self, název). self, ten je povinný a ten se automaticky nahrazuje jménem instance, tedy v našem případě self = mojeOpicka. No a druhý argument nazev za ten se dosadí to, co předáváme v závorce, tedy v našem případě 'Jonanka'. Můžu tedy směle říci že následující dva řádky jsou v našem případě jakoby totožné totožné:
self.nick=nazev
mojeOpicka.nick='Johanka'
Proč nepoužíváme ve třídě místo self.nick přímo mojeOpicka.nick? Hlavně proto, že můžeme vytvářet i jiné opičky než mojeOpicka::
opicka1=Opicky()
opicka2=Opicky()
opicka1.jmeno('Skokan') # zde se self = 'opicka1'
opicka2.jmeno('Lezoun') # zde se self = 'opicka2'
A proč nepoužíváme místo self.nick přímo nick? Bez self? Proměnnou nick samozřejmě použít můžeme, ale bude se jednat o pouhou lokální proměnnou, která zaniká při opuštění metody (funkce) jmeno().
mojeOpicka.nick je tzv. proměnná instance nebo také instanční proměnná. Jak již název napovídá, je hodně podobná obyčejné proměnné. Stejně jako mohu napsat:
pocetZubu=0
stejně tak mohu napsat:
>>> mojeOpicka.pocetZubu=12 # vyzkousejte na prikazove radce
>>> print mojeOpicka.pocetZubu
12
# Pokud jí jeden zub vypadne :-D, mohu napsat
>>> mojeOpicka.pocetZubu = mojeOpicka.pocetZubu - 1
Opička říká své jméno
Spustím-li výše uvedený program a zkusím-li v shellu zjistit jméno opičky, dostanu tuto chybovou hlášku:
Ahoj, já jsem instance třídy Opicky!
>>> mojeOpicka.jmeno()
Traceback (most recent call last):
File "", line 1, in ?
TypeError: jmeno() takes exactly 2 arguments (1 given)
>>>
Bud si mohu nadefinovat jinou metodu, která bude čistě říkat jméno nebo využít fíglu - tzv. dobrovolných argumentů.
Dobrovolné argumenty
Co se to děje? Proč to nejde? Naše metoda jmeno definována tak, že jí jeden argument předat musíme. Když jí ho nepředáme, hlásí chybu, že jí něco chybí. Vyzkoušejte si to! - mojeOpicka.jmeno(). Něco v těch závorkách být musí, něco, co se musí přiřadit do proměnné nazev, nebo to musíme naprogramovat tak, aby nemuselo.
Zde se nám hodí dobrovolné, tzv. implicitní hodnoty argumentů. Při volání metody je pak možné tyto argumenty vynechat a bude jim zcela automaticky přiřazena implicitní hodnota. Náš příklad bude tedy vypadat takto:
def jmeno(self, nazev=None):
...
Takže, když napíšeme mojeOpicka.jmeno() (bez argumentu), tak se automaticky do proměnné nazev uloží None. Jinak se do nazev ukládá předané jméno. A toho můžeme využít uvnitř, kde pomocí if tyto dva stavy rozlišíme a v jednom případě budeme dělat přiřazení self.nick=nazev a v druhém tisk print self.nick.
Úkol
- Dokončete definici třídy podle předchozího odstavce, aby fungovala.
- Naučte opičku říkat svojí hmotnost. Podobně jako u jména jí to nejdříve musíte naučit, a pak to ona musí umět říci.