Než se dnes začneme zabývat třídami, podíváme na objekty.
Co pro programátory znamená slovo objekt?
V Pythonu je to jednoduché – každá hodnota (tj. něco, co můžeš uložit do proměnné, vrátit z funkce nebo třeba seznamu) je objekt. Některé jazyky (třeba Javascript, C++ nebo Java) mají i jiné hodnoty než objekty, v některých jazycích (třeba v C) objekty vůbec nejsou. Ale v Pythonu mezi hodnotou a objektem není rozdíl, takže je na jednu stranu trošku složitější pochopit, v čem spočívá ta „objektovitost“, ale na druhou stranu to zase není potřeba vědět do detailů.
Základní vlastnost objektů je to, že obsahují jak data
(informace), tak chování – instrukce nebo metody,
které s těmito daty pracují.
Třeba řetězce v Pythonu obsahují jak informace
(nějakou sekvenci znaků), tak užitečné metody jako
upper
nebo count
.
Kdyby řetězce nebyly objekty, musel by Python mít
spoustu funkcí jako str_upper
a str_count
.
Objekty spojují data a funkčnost dohromady.
Možná namítneš, že třeba len
je funkce.
Je to tak, Python není „stoprocentně“ objektový jazyk.
Funkce len
ale funguje i na
objektech, které s řetězci nemají nic společného.
Data každého objektu jsou specifická pro konkrétní
objekt ("abc"
obsahuje jiné znaky než
"def"
), ale funkčnost – metody – bývají
společné pro všechny objekty daného typu.
Třeba řetězcová metoda count()
by se dala
napsat zhruba jako:
def count(retezec, znak):
pocet = 0
for c in retezec:
if c == znak:
pocet = pocet + 1
return pocet
… a ačkoliv bude vracet jinou hodnotu pro každý řetězec, samotná metoda je společná všem řetězcům.
Tohle společné chování určuje typ (angl. type) neboli třída (angl. class) daného objektu.
V historických verzích Pythonu byl rozdíl mezi „typem“ a „třídou“, ale dnes už jsou to synonyma.
Typ objektu umí zjistit funkce type
:
>>> type(0)
<class 'int'>
>>> type(True)
<class 'bool'>
>>> type("abc")
<class 'str'>
>>> with open('soubor.txt') as f:
... type(f)
...
<class '_io.TextIOWrapper'>
Takže type
vrací nějaké třídy.
A co je to třída? Popis, jak se chovají všechny objekty
daného typu.
Většinu tříd jde navíc v Pythonu zavolat, jako by to byly funkce, a vytvořit tak nový objekt dané třídy:
>>> trida_retezcu = type("abc")
>>> trida_retezcu(8)
'8'
>>> trida_retezcu([1, 2, 3])
'[1, 2, 3]'
Chová se to stejně jako funkce str
! Není to podivné?
Tady se musím omluvit:
materiály k funkcím
tak trochu lhaly. Funkce str
, int
, float
apod. totiž vůbec
nejsou funkce – jsou to právě třídy.
>>> str
<class 'str'>
>>> type('abcdefgh')
<class 'str'>
>>> type('abcdefgh') == str
True
Ale dají se, podobně jako funkce, zavolat. Třída tedy většinou obsahuje nejen „popis“, jak se objekty daného typu budou chovat, ale umí i objekty daného typu vytvořit.
A proč najednou tolik informací o třídách? Protože si zkusíme napsat třídu vlastní.
Třídu se hodí napsat, když plánuješ mít ve svém programu více objektů s podobným chováním. Třeba karetní hra by mohla mít třídu Karta, webová aplikace třídu Uživatel, tabulkový procesor třídu Řádek.
My teď potřebujeme napsat program o zvířátkách. Začni tím, že napíšeš třídu pro koťátka, která umí mňoukat:
class Kotatko:
def zamnoukej(self):
print("Mňau!")
Tak jako se funkce definují pomocí def
,
třídy mají klíčové slovo class
,
za které napíšeš jméno třídy, dvojtečku,
a pak odsazené tělo třídy.
Podobně jako def
dělá funkce, příkaz
class
udělá novou třídu a přiřadí ji
do proměnné daného jména (tady Kotatko
).
Třídy se tradičně pojmenovávají s velkým písmenem, aby se nepletly s „normálními“ hodnotami.
Základní třídy (str
, int
atd.)
velká písmena nemají, a to hlavně z historických
důvodů – původně to byly opravdu funkce.
V těle třídy můžeš definovat metody, které vypadají
úplně jako funkce – jen mají první argument self
.
Ten si ale vysvětlíme později – zamňoukání má přednost:
# Vytvoření konkrétního objektu
kotatko = Kotatko()
# Volání metody
kotatko.zamnoukej()
V tomhle příkladu si dej pozor na velikost písmen:
Kotatko
(s velkým K) je třída – popis, jak
se koťátka chovají. kotatko
(s malým k)
je konkrétní objekt (angl. instance) té třídy:
hodnota, která reprezentuje kotě.
Onen konkrétní objekt vytvoříme zavoláním třídy,
stejně jako zavoláním str()
se dá vytvořit
konkrétní řetězec.
Mňau!
Objekty vytvořené z „vlastních“ tříd mají jednu
vlastnost, kterou třídy jako str
nedovolují: možnost si definovat vlastní
atributy – informace, které se uloží k danému
objektu.
Atributy se označují tak, že mezi hodnotu a jméno
jejího atributu napíšeš tečku:
mourek = Kotatko()
mourek.jmeno = 'Mourek'
micka = Kotatko()
micka.jmeno = 'Micka'
print(mourek.jmeno)
print(micka.jmeno)
Na začátku jsme si řekly, že objekty spojují chování a data. Chování je definováno ve třídě, data se schovávají právě v atributech jednotlivých objektů. Podle atributů jako jméno můžeš jednotlivá koťátka rozlišit.
Asi sis všimla, že tečkou se dostaneš jak k metodám převzaným z třídy, tak k atributům specifickým pro konkrétní objekt. Co se stane, když má atribut stejné jméno jako metoda z třídy? Vyzkoušej si to:
micka = Kotatko()
micka.zamnoukej = 12345
micka.zamnoukej()
self
A teď se na chvíli vrátíme k metodám,
konkrétně k parametru self
.
Každá metoda má přístup ke konkrétnímu objektu, na
kterém pracuje, právě přes argument self
.
Teď, když máš koťátka pojmenovaná,
můžeš pomocí self
rozjet dialog:
class Kotatko:
def zamnoukej(self):
print("{}: Mňau!".format(self.jmeno))
mourek = Kotatko()
mourek.jmeno = 'Mourek'
micka = Kotatko()
micka.jmeno = 'Micka'
mourek.zamnoukej()
micka.zamnoukej()
Co se stalo? Výraz mourek.zamnoukej
udělá metodu, která, když ji zavoláš,
předá objekt mourek
jako první argument
funkce zamnoukej
.
Tohle je to, čím se metoda liší od normální funkce: metoda si „pamatuje“ objekt, na kterém pracuje.
A takový první argument, který obsahuje konkrétní
objekt právě definované třídy, se tradičně pojmenovává self
.
(Když ho pojmenuješ jinak, ostatní programátoři se na tebe budou koukat hodně
divně.)
A může taková metoda brát víc než jeden argument?
Může – self
se doplní na první místo,
a zbytek argumentů se vezme z volání metody.
Třeba:
class Kotatko:
def zamnoukej(self):
print("{}: Mňau!".format(self.jmeno))
def snez(self, jidlo):
print("{}: Mňau mňau! {} mi chutná!".format(self.jmeno, jidlo))
mourek = Kotatko()
mourek.jmeno = 'Mourek'
mourek.snez('ryba')
__init__
A když jsme u argumentů, je ještě jedno místo,
kde můžeš třídě poslat argumenty: když vytváříš
nový objekt (voláním třídy).
Dá se tak hezky vyřešit problém, který možná vidíš
v předchozím kódu: aktuálně každé koťátko potřebuje,
aby se mu po vytvoření nastavilo jméno, jinak
metoda zamnoukej
nebude fungovat.
Třída se ale dá udělat i tak, že půjde jméno nastavit
už při vytváření, takhle:
mourek = Kotatko(jmeno='Mourek')
Na tohle používá Python metodu,
která se jmenuje __init__
(dvě podtržítka,
init
, dvě podtržítka).
To „opodtržítkování“ znamená, že tohle jméno je nějakým způsobem speciální.
Metoda __init__
se totiž zavolá
automaticky, když se vytvoří nový objekt.
Dá se tedy napsat:
class Kotatko:
def __init__(self, jmeno):
self.jmeno = jmeno
def zamnoukej(self):
print("{}: Mňau!".format(self.jmeno))
def snez(self, jidlo):
print("{}: Mňau mňau! {} mi chutná!".format(self.jmeno, jidlo))
mourek = Kotatko('Mourek')
mourek.zamnoukej()
A teď už není možnost, jak vytvořit koťátko bez jména,
takže zamnoukej
bude vždycky fungovat.
Podobných „opodtržítkovaných“ metod je víc,
třeba __str__
se volá, když je potřeba
převést objekt na řetězec:
class Kotatko:
def __init__(self, jmeno):
self.jmeno = jmeno
def __str__(self):
return '<Kotatko jmenem {}>'.format(self.jmeno)
def zamnoukej(self):
print("{}: Mňau!".format(self.jmeno))
def snez(self, jidlo):
print("{}: Mňau mňau! {} mi chutná!".format(self.jmeno, jidlo))
mourek = Kotatko('Mourek')
print(mourek)
Teď, když už umíš dělat koťátka, zkus vytvořit třídu pro kočku.
zamnoukej
.je_ziva
.uber_zivot
.snez
, která bere 1 argument -
nějaké konkrétní jídlo (řetězec). Pokud je toto jídlo "ryba"
, kočce se obnoví
jeden život (pokud teda už není mrtvá, nebo nemá maximální počet životů).A to je o samotných třídách zatím vše. Příště si něco řekneme o dědičnosti. A o štěňátkách.
{ "data": { "sessionMaterial": { "id": "session-material:2019/pyladies-brno-jaro-st:class:0", "title": "Třídy", "html": "\n \n \n\n <h1>Hodnoty a objekty</h1>\n<p>Než se dnes začneme zabývat třídami,\npodíváme na objekty.</p>\n<p>Co pro programátory znamená slovo <em>objekt</em>?</p>\n<p>V Pythonu je to jednoduché – každá hodnota\n(tj. něco, co můžeš uložit do proměnné, vrátit\nz funkce nebo třeba seznamu) je objekt.\nNěkteré jazyky (třeba Javascript, C++ nebo Java) mají\ni jiné hodnoty než objekty, v některých\njazycích (třeba v C) objekty vůbec nejsou.\nAle v Pythonu mezi hodnotou a objektem není rozdíl,\ntakže je na jednu stranu trošku složitější pochopit,\nv čem spočívá ta „objektovitost“, ale na druhou stranu\nto zase není potřeba vědět do detailů.</p>\n<p>Základní vlastnost objektů je to, že obsahují jak data\n(informace), tak <em>chování</em> – instrukce nebo metody,\nkteré s těmito daty pracují.\nTřeba řetězce v Pythonu obsahují jak informace\n(nějakou sekvenci znaků), tak užitečné metody jako\n<code>upper</code> nebo <code>count</code>.\nKdyby řetězce nebyly objekty, musel by Python mít\nspoustu funkcí jako <code>str_upper</code> a <code>str_count</code>.\nObjekty spojují data a funkčnost dohromady.</p>\n<div class=\"admonition note\"><p>Možná namítneš, že třeba <code>len</code> je funkce.\nJe to tak, Python není „stoprocentně“ objektový jazyk.\nFunkce <code>len</code> ale funguje i na\nobjektech, které s řetězci nemají nic společného.</p>\n</div><h1>Třídy</h1>\n<p>Data každého objektu jsou specifická pro konkrétní\nobjekt (<code>"abc"</code> obsahuje jiné znaky než\n<code>"def"</code>), ale funkčnost – metody – bývají\nspolečné pro všechny objekty daného typu.\nTřeba řetězcová metoda <code>count()</code> by se dala\nnapsat zhruba jako:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"k\">def</span> <span class=\"nf\">count</span><span class=\"p\">(</span><span class=\"n\">retezec</span><span class=\"p\">,</span> <span class=\"n\">znak</span><span class=\"p\">):</span>\n <span class=\"n\">pocet</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n <span class=\"k\">for</span> <span class=\"n\">c</span> <span class=\"ow\">in</span> <span class=\"n\">retezec</span><span class=\"p\">:</span>\n <span class=\"k\">if</span> <span class=\"n\">c</span> <span class=\"o\">==</span> <span class=\"n\">znak</span><span class=\"p\">:</span>\n <span class=\"n\">pocet</span> <span class=\"o\">=</span> <span class=\"n\">pocet</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>\n <span class=\"k\">return</span> <span class=\"n\">pocet</span>\n</pre></div><p>… a ačkoliv bude vracet jinou hodnotu pro každý řetězec,\nsamotná metoda je společná všem řetězcům.</p>\n<p>Tohle společné chování určuje\n<em>typ</em> (angl. <em>type</em>) neboli <em>třída</em> (angl. <em>class</em>) daného objektu.</p>\n<div class=\"admonition note\"><p>V historických verzích Pythonu byl rozdíl mezi „typem“\na „třídou“, ale dnes už jsou to synonyma.</p>\n</div><p>Typ objektu umí zjistit funkce <code>type</code>:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"gp\">>>> </span><span class=\"nb\">type</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">)</span>\n<span class=\"go\"><class 'int'></span>\n<span class=\"gp\">>>> </span><span class=\"nb\">type</span><span class=\"p\">(</span><span class=\"bp\">True</span><span class=\"p\">)</span>\n<span class=\"go\"><class 'bool'></span>\n<span class=\"gp\">>>> </span><span class=\"nb\">type</span><span class=\"p\">(</span><span class=\"s2\">"abc"</span><span class=\"p\">)</span>\n<span class=\"go\"><class 'str'></span>\n<span class=\"gp\">>>> </span><span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"s1\">'soubor.txt'</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f</span><span class=\"p\">:</span>\n<span class=\"gp\">... </span> <span class=\"nb\">type</span><span class=\"p\">(</span><span class=\"n\">f</span><span class=\"p\">)</span>\n<span class=\"gp\">... </span>\n<span class=\"go\"><class '_io.TextIOWrapper'></span>\n</pre></div><p>Takže <code>type</code> vrací nějaké třídy.\nA co je to třída? Popis, jak se chovají všechny objekty\ndaného typu.</p>\n<p>Většinu tříd jde navíc v Pythonu zavolat, jako by\nto byly funkce, a vytvořit tak nový objekt dané třídy:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"gp\">>>> </span><span class=\"n\">trida_retezcu</span> <span class=\"o\">=</span> <span class=\"nb\">type</span><span class=\"p\">(</span><span class=\"s2\">"abc"</span><span class=\"p\">)</span>\n<span class=\"gp\">>>> </span><span class=\"n\">trida_retezcu</span><span class=\"p\">(</span><span class=\"mi\">8</span><span class=\"p\">)</span>\n<span class=\"go\">'8'</span>\n<span class=\"gp\">>>> </span><span class=\"n\">trida_retezcu</span><span class=\"p\">([</span><span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"mi\">3</span><span class=\"p\">])</span>\n<span class=\"go\">'[1, 2, 3]'</span>\n</pre></div><p>Chová se to stejně jako funkce <code>str</code>! Není to podivné?</p>\n<p>Tady se musím omluvit:\n<a href=\"/2019/pyladies-brno-jaro-st/beginners/functions/\">materiály k funkcím</a>\ntak trochu lhaly. Funkce <code>str</code>, <code>int</code>, <code>float</code> apod. totiž vůbec\nnejsou funkce – jsou to právě třídy.</p>\n<div class=\"highlight\"><pre><span></span><span class=\"gp\">>>> </span><span class=\"nb\">str</span>\n<span class=\"go\"><class 'str'></span>\n<span class=\"gp\">>>> </span><span class=\"nb\">type</span><span class=\"p\">(</span><span class=\"s1\">'abcdefgh'</span><span class=\"p\">)</span>\n<span class=\"go\"><class 'str'></span>\n<span class=\"gp\">>>> </span><span class=\"nb\">type</span><span class=\"p\">(</span><span class=\"s1\">'abcdefgh'</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"nb\">str</span>\n<span class=\"go\">True</span>\n</pre></div><p>Ale dají se, podobně jako funkce, zavolat.\nTřída tedy většinou obsahuje nejen „popis“, jak se\nobjekty daného typu budou chovat, ale umí i objekty\ndaného typu vytvořit.</p>\n<h2>Vlastní třídy</h2>\n<p>A proč najednou tolik informací o třídách?\nProtože si zkusíme napsat třídu vlastní.</p>\n<p>Třídu se hodí napsat, když plánuješ mít ve svém\nprogramu více objektů s podobným chováním.\nTřeba karetní hra by mohla mít třídu Karta,\nwebová aplikace třídu Uživatel,\ntabulkový procesor třídu Řádek.</p>\n<p>My teď potřebujeme napsat program o zvířátkách.\nZačni tím, že napíšeš třídu pro koťátka, která umí mňoukat:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"k\">class</span> <span class=\"nc\">Kotatko</span><span class=\"p\">:</span>\n <span class=\"k\">def</span> <span class=\"nf\">zamnoukej</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s2\">"Mňau!"</span><span class=\"p\">)</span>\n</pre></div><p>Tak jako se funkce definují pomocí <code>def</code>,\ntřídy mají klíčové slovo <code>class</code>,\nza které napíšeš jméno třídy, dvojtečku,\na pak odsazené tělo třídy.\nPodobně jako <code>def</code> dělá funkce, příkaz\n<code>class</code> udělá novou třídu a přiřadí ji\ndo proměnné daného jména (tady <code>Kotatko</code>).</p>\n<p>Třídy se tradičně pojmenovávají s velkým písmenem,\naby se nepletly s „normálními“ hodnotami.</p>\n<div class=\"admonition note\"><p>Základní třídy (<code>str</code>, <code>int</code> atd.)\nvelká písmena nemají, a to hlavně z historických\ndůvodů – původně to byly opravdu funkce.</p>\n</div><p>V těle třídy můžeš definovat metody, které vypadají\núplně jako funkce – jen mají první argument <code>self</code>.\nTen si ale vysvětlíme později – zamňoukání má přednost:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"c1\"># Vytvoření konkrétního objektu</span>\n<span class=\"n\">kotatko</span> <span class=\"o\">=</span> <span class=\"n\">Kotatko</span><span class=\"p\">()</span>\n\n<span class=\"c1\"># Volání metody</span>\n<span class=\"n\">kotatko</span><span class=\"o\">.</span><span class=\"n\">zamnoukej</span><span class=\"p\">()</span>\n</pre></div><p>V tomhle příkladu si dej pozor na velikost písmen:\n<code>Kotatko</code> (s velkým K) je třída – popis, jak\nse koťátka chovají. <code>kotatko</code> (s malým k)\nje konkrétní objekt (angl. <em>instance</em>) té třídy:\nhodnota, která reprezentuje kotě.\nOnen konkrétní objekt vytvoříme zavoláním třídy,\nstejně jako zavoláním <code>str()</code> se dá vytvořit\nkonkrétní řetězec.</p>\n<p>Mňau!</p>\n<h2>Atributy</h2>\n<p>Objekty vytvořené z „vlastních“ tříd mají jednu\nvlastnost, kterou třídy jako <code>str</code>\nnedovolují: možnost si definovat vlastní\n<em>atributy</em> – informace, které se uloží k danému\nobjektu.\nAtributy se označují tak, že mezi hodnotu a jméno\njejího atributu napíšeš tečku:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"n\">mourek</span> <span class=\"o\">=</span> <span class=\"n\">Kotatko</span><span class=\"p\">()</span>\n<span class=\"n\">mourek</span><span class=\"o\">.</span><span class=\"n\">jmeno</span> <span class=\"o\">=</span> <span class=\"s1\">'Mourek'</span>\n\n<span class=\"n\">micka</span> <span class=\"o\">=</span> <span class=\"n\">Kotatko</span><span class=\"p\">()</span>\n<span class=\"n\">micka</span><span class=\"o\">.</span><span class=\"n\">jmeno</span> <span class=\"o\">=</span> <span class=\"s1\">'Micka'</span>\n\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"n\">mourek</span><span class=\"o\">.</span><span class=\"n\">jmeno</span><span class=\"p\">)</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"n\">micka</span><span class=\"o\">.</span><span class=\"n\">jmeno</span><span class=\"p\">)</span>\n</pre></div><p>Na začátku jsme si řekly, že objekty spojují chování\na data.\nChování je definováno ve třídě, data se schovávají\nprávě v atributech jednotlivých objektů.\nPodle atributů jako jméno můžeš jednotlivá koťátka\nrozlišit.</p>\n<div class=\"admonition note\"><p>Asi sis všimla, že tečkou se dostaneš jak k metodám\npřevzaným z třídy, tak k atributům specifickým\npro konkrétní objekt.\nCo se stane, když má atribut stejné jméno jako\nmetoda z třídy? Vyzkoušej si to:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"n\">micka</span> <span class=\"o\">=</span> <span class=\"n\">Kotatko</span><span class=\"p\">()</span>\n<span class=\"n\">micka</span><span class=\"o\">.</span><span class=\"n\">zamnoukej</span> <span class=\"o\">=</span> <span class=\"mi\">12345</span>\n<span class=\"n\">micka</span><span class=\"o\">.</span><span class=\"n\">zamnoukej</span><span class=\"p\">()</span>\n</pre></div></div><h2>Parametr <code>self</code></h2>\n<p>A teď se na chvíli vrátíme k metodám,\nkonkrétně k parametru <code>self</code>.</p>\n<p>Každá metoda má přístup ke konkrétnímu objektu, na\nkterém pracuje, právě přes argument <code>self</code>.\nTeď, když máš koťátka pojmenovaná,\nmůžeš pomocí <code>self</code> rozjet dialog:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"k\">class</span> <span class=\"nc\">Kotatko</span><span class=\"p\">:</span>\n <span class=\"k\">def</span> <span class=\"nf\">zamnoukej</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s2\">"{}: Mňau!"</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">jmeno</span><span class=\"p\">))</span>\n\n<span class=\"n\">mourek</span> <span class=\"o\">=</span> <span class=\"n\">Kotatko</span><span class=\"p\">()</span>\n<span class=\"n\">mourek</span><span class=\"o\">.</span><span class=\"n\">jmeno</span> <span class=\"o\">=</span> <span class=\"s1\">'Mourek'</span>\n\n<span class=\"n\">micka</span> <span class=\"o\">=</span> <span class=\"n\">Kotatko</span><span class=\"p\">()</span>\n<span class=\"n\">micka</span><span class=\"o\">.</span><span class=\"n\">jmeno</span> <span class=\"o\">=</span> <span class=\"s1\">'Micka'</span>\n\n<span class=\"n\">mourek</span><span class=\"o\">.</span><span class=\"n\">zamnoukej</span><span class=\"p\">()</span>\n<span class=\"n\">micka</span><span class=\"o\">.</span><span class=\"n\">zamnoukej</span><span class=\"p\">()</span>\n</pre></div><p>Co se stalo? Výraz <code>mourek.zamnoukej</code> udělá <em>metodu</em>, která, když ji zavoláš,\npředá objekt <code>mourek</code> jako první argument\nfunkce <code>zamnoukej</code>.</p>\n<div class=\"admonition note\"><p>Tohle je to, čím se <em>metoda</em> liší od normální <em>funkce</em>:\nmetoda si „pamatuje“ objekt, na kterém pracuje.</p>\n</div><p>A takový první argument, který obsahuje konkrétní\nobjekt právě definované třídy, se tradičně pojmenovává <code>self</code>.\n(Když ho pojmenuješ jinak, ostatní programátoři se na tebe budou koukat hodně\ndivně.)</p>\n<p>A může taková metoda brát víc než jeden argument?\nMůže – <code>self</code> se doplní na první místo,\na zbytek argumentů se vezme z volání metody.\nTřeba:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"k\">class</span> <span class=\"nc\">Kotatko</span><span class=\"p\">:</span>\n <span class=\"k\">def</span> <span class=\"nf\">zamnoukej</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s2\">"{}: Mňau!"</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">jmeno</span><span class=\"p\">))</span>\n\n <span class=\"k\">def</span> <span class=\"nf\">snez</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">jidlo</span><span class=\"p\">):</span>\n <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s2\">"{}: Mňau mňau! {} mi chutná!"</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">jmeno</span><span class=\"p\">,</span> <span class=\"n\">jidlo</span><span class=\"p\">))</span>\n\n<span class=\"n\">mourek</span> <span class=\"o\">=</span> <span class=\"n\">Kotatko</span><span class=\"p\">()</span>\n<span class=\"n\">mourek</span><span class=\"o\">.</span><span class=\"n\">jmeno</span> <span class=\"o\">=</span> <span class=\"s1\">'Mourek'</span>\n<span class=\"n\">mourek</span><span class=\"o\">.</span><span class=\"n\">snez</span><span class=\"p\">(</span><span class=\"s1\">'ryba'</span><span class=\"p\">)</span>\n</pre></div><h2>Metoda <code>__init__</code></h2>\n<p>A když jsme u argumentů, je ještě jedno místo,\nkde můžeš třídě poslat argumenty: když vytváříš\nnový objekt (voláním třídy).\nDá se tak hezky vyřešit problém, který možná vidíš\nv předchozím kódu: aktuálně každé koťátko potřebuje,\naby se mu po vytvoření nastavilo jméno, jinak\nmetoda <code>zamnoukej</code> nebude fungovat.\nTřída se ale dá udělat i tak, že půjde jméno nastavit\nuž při vytváření, takhle:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"n\">mourek</span> <span class=\"o\">=</span> <span class=\"n\">Kotatko</span><span class=\"p\">(</span><span class=\"n\">jmeno</span><span class=\"o\">=</span><span class=\"s1\">'Mourek'</span><span class=\"p\">)</span>\n</pre></div><p>Na tohle používá Python metodu,\nkterá se jmenuje <code>__init__</code> (dvě podtržítka,\n<code>init</code>, dvě podtržítka).\nTo „opodtržítkování“ znamená, že tohle jméno je nějakým způsobem speciální.\nMetoda <code>__init__</code> se totiž zavolá\nautomaticky, když se vytvoří nový objekt.\nDá se tedy napsat:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"k\">class</span> <span class=\"nc\">Kotatko</span><span class=\"p\">:</span>\n <span class=\"k\">def</span> <span class=\"fm\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">jmeno</span><span class=\"p\">):</span>\n <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">jmeno</span> <span class=\"o\">=</span> <span class=\"n\">jmeno</span>\n\n <span class=\"k\">def</span> <span class=\"nf\">zamnoukej</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s2\">"{}: Mňau!"</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">jmeno</span><span class=\"p\">))</span>\n\n <span class=\"k\">def</span> <span class=\"nf\">snez</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">jidlo</span><span class=\"p\">):</span>\n <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s2\">"{}: Mňau mňau! {} mi chutná!"</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">jmeno</span><span class=\"p\">,</span> <span class=\"n\">jidlo</span><span class=\"p\">))</span>\n\n<span class=\"n\">mourek</span> <span class=\"o\">=</span> <span class=\"n\">Kotatko</span><span class=\"p\">(</span><span class=\"s1\">'Mourek'</span><span class=\"p\">)</span>\n<span class=\"n\">mourek</span><span class=\"o\">.</span><span class=\"n\">zamnoukej</span><span class=\"p\">()</span>\n</pre></div><p>A teď už není možnost, jak vytvořit koťátko bez jména,\ntakže <code>zamnoukej</code> bude vždycky fungovat.</p>\n<p>Podobných „opodtržítkovaných“ metod je víc,\ntřeba <code>__str__</code> se volá, když je potřeba\npřevést objekt na řetězec:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"k\">class</span> <span class=\"nc\">Kotatko</span><span class=\"p\">:</span>\n <span class=\"k\">def</span> <span class=\"fm\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">jmeno</span><span class=\"p\">):</span>\n <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">jmeno</span> <span class=\"o\">=</span> <span class=\"n\">jmeno</span>\n\n <span class=\"k\">def</span> <span class=\"fm\">__str__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n <span class=\"k\">return</span> <span class=\"s1\">'<Kotatko jmenem {}>'</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">jmeno</span><span class=\"p\">)</span>\n\n <span class=\"k\">def</span> <span class=\"nf\">zamnoukej</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s2\">"{}: Mňau!"</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">jmeno</span><span class=\"p\">))</span>\n\n <span class=\"k\">def</span> <span class=\"nf\">snez</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">jidlo</span><span class=\"p\">):</span>\n <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s2\">"{}: Mňau mňau! {} mi chutná!"</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">jmeno</span><span class=\"p\">,</span> <span class=\"n\">jidlo</span><span class=\"p\">))</span>\n\n<span class=\"n\">mourek</span> <span class=\"o\">=</span> <span class=\"n\">Kotatko</span><span class=\"p\">(</span><span class=\"s1\">'Mourek'</span><span class=\"p\">)</span>\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"n\">mourek</span><span class=\"p\">)</span>\n</pre></div><h2>Cvičení: Kočka</h2>\n<p>Teď, když už umíš dělat koťátka, zkus vytvořit třídu pro kočku.</p>\n<ul>\n<li>Kočka umí mňoukat metodou <code>zamnoukej</code>.</li>\n<li>Kočka má na začátku (při vytvoření) 9 životů\n(nemůže mít nikdy víc než 9 nebo míň než 0!).</li>\n<li>Kočka umí říct, jestli je živá (nemá 0 životů), metodou <code>je_ziva</code>.</li>\n<li>Kočka může ztratit život metodou <code>uber_zivot</code>.</li>\n<li>Kočku můžeš nakrmit metodou <code>snez</code>, která bere 1 argument -\nnějaké konkrétní jídlo (řetězec). Pokud je toto jídlo <code>"ryba"</code>, kočce se obnoví\njeden život (pokud teda už není mrtvá, nebo nemá maximální počet životů).</li>\n</ul>\n<div class=\"solution\" id=\"solution-0\">\n <h3>Řešení</h3>\n <div class=\"solution-cover\">\n <a href=\"/2019/pyladies-brno-jaro-st/beginners/class/index/solutions/0/\"><span class=\"link-text\">Ukázat řešení</span></a>\n </div>\n <div class=\"solution-body\" aria-hidden=\"true\">\n <div class=\"highlight\"><pre><span></span><span class=\"k\">class</span> <span class=\"nc\">Kocka</span><span class=\"p\">:</span>\n <span class=\"k\">def</span> <span class=\"fm\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span> <span class=\"c1\"># Init funkce nemusi brat jako parametr</span>\n <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">pocet_zivotu</span> <span class=\"o\">=</span> <span class=\"mi\">9</span> <span class=\"c1\"># pocet zivotu, ten je pokazde 9.</span>\n\n <span class=\"k\">def</span> <span class=\"nf\">zamnoukej</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s2\">"Mnau, mnau, mnauuu!"</span><span class=\"p\">)</span>\n\n <span class=\"k\">def</span> <span class=\"nf\">je_ziva</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n <span class=\"k\">return</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">pocet_zivotu</span> <span class=\"o\">></span> <span class=\"mi\">0</span>\n\n <span class=\"k\">def</span> <span class=\"nf\">uber_zivot</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">je_ziva</span><span class=\"p\">():</span>\n <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s2\">"Nemuzes zabit uz mrtvou kocku!"</span><span class=\"p\">)</span>\n <span class=\"k\">else</span><span class=\"p\">:</span>\n <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">pocet_zivotu</span> <span class=\"o\">-=</span> <span class=\"mi\">1</span>\n\n <span class=\"k\">def</span> <span class=\"nf\">snez</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">jidlo</span><span class=\"p\">):</span>\n <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">je_ziva</span><span class=\"p\">():</span>\n <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s2\">"Je zbytecne krmit mrtvou kocku!"</span><span class=\"p\">)</span>\n <span class=\"k\">return</span>\n <span class=\"k\">if</span> <span class=\"n\">jidlo</span> <span class=\"o\">==</span> <span class=\"s2\">"ryba"</span> <span class=\"ow\">and</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">pocet_zivotu</span> <span class=\"o\"><</span> <span class=\"mi\">9</span><span class=\"p\">:</span>\n <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">pocet_zivotu</span> <span class=\"o\">+=</span> <span class=\"mi\">1</span>\n <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s2\">"Kocka spapala rybu a obnovil se ji jeden zivot."</span><span class=\"p\">)</span>\n <span class=\"k\">else</span><span class=\"p\">:</span>\n <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s2\">"Kocka se krmi."</span><span class=\"p\">)</span>\n</pre></div>\n </div>\n</div><p>A to je o samotných třídách zatím vše.\n<a href=\"/2019/pyladies-brno-jaro-st/beginners/inheritance/\">Příště</a> si něco řekneme o dědičnosti.\nA o štěňátkách.</p>\n\n\n " } } }