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 jiných jazycích než Python 3 můžou slova „typ“ a „třída“ označovat různé věci. Pro nás to budou 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'>
A co je to třída? Třída je popis, jak se všechny objekty daného typu chovají.
Nepříklad <class 'int'>
obsahuje všechno, co je společné všem celým číslům:
že (a jak) se dají sčítat, jak takové číslo převést na řetězec, a tak dále.
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 její objekty budou chovat, ale „umí“ takové objekty i 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 – napřed zkus zamňoukat:
# 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ě.
Když definuješ třídu (pomocí bloku class
), neznamená to, že v tvém
programu je nějaké koťátko.
Třída je jako recept nebo manuál: když si koupíš kuchařku, teoreticky víš
jak upéct dort, jak bude takový dort vypadat a že se dá sníst.
Ale neznamená to ještě, že máš samotný dort!
Konkrétní objekt vytvoříš až zavoláním třídy.
Stejně jako zavoláním str()
se dá vytvořit konkrétní řetězec,
volání Kotatko()
vytvoří nový objekt tvé třídy, který už můžeš použít.
Mňau!
Objekty vytvořené z „vlastních“ tříd mají funkčnost, 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 jmeno
pak 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
Teď se na chvíli vrať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š v metodě zamnoukej
použít self
a dostat se tak ke jménu daného koťátka:
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.
Když ji pak zavoláš (mourek.zamnoukej()
),
objekt mourek
se předá funkci zamnoukej
jako první argument, self
.
Onen první argument metody můžešw teoreticky pojmenovat i jinak než self
,
ale když to uděláš, ostatní programátoři se na tebe budou koukat hodně divně.
Může taková metoda brát víc než jeden argument?
Může – self
se doplní na první místo,
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__
Co se stane, když koťátku zapomeneš nastavit jméno?
Metoda zamnoukej
přestane fungovat:
>>> micka = Kotatko()
>>> micka.snez('ryba')
Traceback (most recent call last):
File "<zvirata.py>", line 5, in snez
AttributeError: 'Kotatko' object has no attribute 'jmeno'
Bylo by dobré zařídit, aby každé kotě muselo být pojmenované. Jméno potřebujeme předat už při vytváření kotěte, nějak takhle:
mourek = Kotatko(jmeno='Mourek')
To ale zatím nefunguje; musíme na to třídu Kotatko
připravit.
Použijeme na to speciální 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í.
Metodu __init__
totiž Python zavolá
automaticky, když 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 beze jména.
Metoda zamnoukej
bude vždycky fungovat.
Podobných „opodtržítkovaných“ (speciální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)
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/brno-jaro-2019-pondeli: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 jiných jazycích než Python 3 můžou slova „typ“ a „třída“ označovat různé\nvěci. Pro nás to budou 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>A co je to třída? Třída je <em>popis</em>, jak se všechny objekty\ndaného typu chovají.</p>\n<p>Nepříklad <code><class 'int'></code> obsahuje všechno, co je společné všem celým číslům:\nže (a jak) se dají sčítat, jak takové číslo převést na řetězec, a tak dále.</p>\n<h2>Tvoření objektů třídy</h2>\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/brno-jaro-2019-pondeli/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\njejí objekty budou chovat, ale „umí“ takové objekty i 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 – napřed zkus zamňoukat:</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í.\n<code>kotatko</code> (s malým k)\nje konkrétní objekt (angl. <em>instance</em>) té třídy:\nhodnota, která reprezentuje kotě.</p>\n<p>Když definuješ třídu (pomocí bloku <code>class</code>), neznamená to, že v tvém\nprogramu je nějaké koťátko.\nTřída je jako recept nebo manuál: když si koupíš kuchařku, teoreticky víš\njak upéct dort, jak bude takový dort vypadat a že se dá sníst.\nAle neznamená to ještě, že máš samotný dort!</p>\n<p>Konkrétní objekt vytvoříš až zavoláním třídy.\nStejně jako zavoláním <code>str()</code> se dá vytvořit konkrétní řetězec,\nvolání <code>Kotatko()</code> vytvoří nový objekt tvé třídy, který už můžeš použít.</p>\n<p>Mňau!</p>\n<h2>Atributy</h2>\n<p>Objekty vytvořené z „vlastních“ tříd mají funkčnost, kterou třídy jako <code>str</code>\nnedovolují: možnost si definovat vlastní\n<em>atributy</em> – informace, které se uloží k danému objektu.\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 <code>jmeno</code> pak 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>Teď se na chvíli vraťme k metodám. Konkré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á, můžeš v metodě <code>zamnoukej</code> použít <code>self</code>\na dostat se tak ke jménu daného koťátka:</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>.\nKdyž ji pak zavoláš (<code>mourek.zamnoukej()</code>),\nobjekt <code>mourek</code> se předá funkci <code>zamnoukej</code> jako první argument, <code>self</code> .</p>\n<div class=\"admonition note\"><p>Onen první argument metody můžešw teoreticky pojmenovat i jinak než <code>self</code>,\nale když to uděláš, ostatní programátoři se na tebe budou koukat hodně divně.</p>\n</div><p>Může taková metoda brát víc než jeden argument?\nMůže – <code>self</code> se doplní na první místo,\nzbytek 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>Co se stane, když koťátku zapomeneš nastavit jméno?\nMetoda <code>zamnoukej</code> přestane fungovat:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"gp\">>>> </span><span class=\"n\">micka</span> <span class=\"o\">=</span> <span class=\"n\">Kotatko</span><span class=\"p\">()</span>\n<span class=\"gp\">>>> </span><span class=\"n\">micka</span><span class=\"o\">.</span><span class=\"n\">snez</span><span class=\"p\">(</span><span class=\"s1\">'ryba'</span><span class=\"p\">)</span>\n<span class=\"gt\">Traceback (most recent call last):</span>\n File <span class=\"nb\">"<zvirata.py>"</span>, line <span class=\"m\">5</span>, in <span class=\"n\">snez</span>\n<span class=\"gr\">AttributeError</span>: <span class=\"n\">'Kotatko' object has no attribute 'jmeno'</span>\n</pre></div><p>Bylo by dobré zařídit, aby každé kotě muselo být pojmenované.\nJméno potřebujeme předat už při vytváření kotěte, nějak 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>To ale zatím nefunguje; musíme na to třídu <code>Kotatko</code> připravit.</p>\n<p>Použijeme na to speciální 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í.\nMetodu <code>__init__</code> totiž Python zavolá\nautomaticky, když 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 beze jména.\nMetoda <code>zamnoukej</code> bude vždycky fungovat.</p>\n<p>Podobných „opodtržítkovaných“ (speciální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><p>A to je o samotných třídách zatím vše.\n<a href=\"/2019/brno-jaro-2019-pondeli/beginners/inheritance/\">Příště</a> si něco řekneme o dědičnosti.\nA o štěňátkách.</p>\n\n\n " } } }