Subsections

 
9. Třídy

Mechanismus tříd v jazyce Python přináší objektově orientované programování společně s minimem nového syntaxu a sémantiky. Jde o směs různých mechanismů inspirovanou jazyky C++ a Modula-3. V Pythonu třídy, podobně jako moduly, netvoří žádnou bariéru mezi definicí třídy a uživatelem. Python podporuje nejdůležitější mechanismy objektově orientovaného programování: mechanismus dědičnosti tříd umožňuje vícenásobnou dědičnost, odvozená třída může předefinovat libovolnou metodu její rodičovské třídy, metoda může volat metodu rodičovské třídy se stejným jménem, objekty mohou obsahovat libovolné množství soukromých dat...

Podle terminologie jazyka C++ jsou všechny atributy (tj. metody i třídy) veřejné a všechny metody jsou virtuální. Neexistují zde žádné konstruktory a destruktory. Stejně jako v jazyce Modula-3 zde nenajdete žádnou zkratku pro odkazování se na atributy objektu z jeho metod: metoda je definována s jedním explicitním argumentem, reprezentujícím objekt, pro který byla metoda zavolána. Stejně jako ve Smalltalku jsou třídy také objekty, ale v širším slova smyslu - v Pythonu jsou všechny datové typy objekty. Ale, stejně jako v C++ nebo Modula-3, interní typy nemohou být použity jako základní třídy pro rozšíření uživatelem. Podobně jako v C++ může být chování většiny interních operátorů (aritmetické operátory, indexování atd.) předefinováno instancemi této třídy.

 
9.1 Pár slov a použité terminologii

Protože svět postrádá všeobecně akceptovanou terminologii týkající se tříd, budu používat termíny z repertoáru jazyků Smalltalk a C++.

Také vás musím varovat před terminologickým chytákem pro čtenáře, kteří již něco o objektově orientovaném programování vědí: slovo "objekt" v Pythonu nemusí nutně znamenat instanci třídy. Podobně jako v C++ a Modula-3 nejsou v Pythonu všechny typy třídy - základní interní typy jako čísla a seznamy a také některé více exotické typy jako soubory jsou netřídní typy. Nicméně všechny typy v Pythonu sdílí trochu stejné sémantiky, takže je lépe popíšeme používáním slova objekt.

Objekty jsou individuální a více jmen (ve více prostorech jmen) mohou ukazovat na tentýž objekt. V jiných jazycích se tento mechanismus nazývá vytváření odkazů (odkazování, aliasing). Používání odkazů nás nebude příliš zajímat ve spojení s neměnnými datovými typy (čísla, řetězce a tuple), o to větší pozornost vyžaduje při používání proměnných objektů (seznamy, slovníky, typy reprezentující entity mimo program) -- odkazy se totiž chovají podobně jako pointery. Například předání objekty je implementováno jako předání odkazu. A když funkce modifikuje předaný objekt, volaná funkce tuto změnu uvidí - takto se Python vyhnul potřebě dvou různých mechanismů předávání argumentů tak, jak je používá třeba Pascal.

 
9.2 Prostory jmen v jazyce Python

Před samotným povídáním o třídách si nejprve něco řekneme o pravidlech, která Python používá při používání oborů jmen. Pro plné pochopení mechanismu objektově orientovaného programování si nejprve musíme něco povědět o oborech jmen a prostorech jmen. Znalost této problematiky je nutná a bude se hodit i zkušeným programátorům v jazyce Python.

Začněme několika definicemi.

Prostor jmen vytváří mapování ze jmen proměnných na objekty. Většina prostorů jmen je v současnosti implementována za pomoci slovníků. Většinou si ale rozdílu mezi slovníkovou implentací a jiným druhem implementace téměř nevšimnete (s výjimkou jejich rychlosti). V budoucnosti se to však může změnit. Příkladem prostoru jmen může být interní prostor jmen (obsahující funkce jako abs() a jména interních výjimek), globální prostor jmen určitého modulu (obsahující globální proměnné modulu) nebo třeba lokální prostor jmen uvnitř nějaké funkce. Atributy objektů také tvoří prostory jmen. Neexistuje žádná závislost mezi jmény v různých prostorech jmen - například dva různé moduly mohou definovat funkci "maximize" aniž by se navzájem ovlivňovaly -- uživatelé modulu musí ale před názvem funkce uvést jméno modulu.

Slovo atribut používám pro jakékoli jméno následující tečku -- například ve výrazu z.real je real atributem objektu z. Přesněji řečeno -- odkazy na jména uvnitř modulu jsou také odkazy na atributy: ve výrazu jméno_modulu.funkce je jméno_modulu objekt typu modul a funkce je jeho atributem. Atributy modulu jsou přímo mapovány do jeho globálního prostoru jmen, tj. sdílí jeden a ten samý prostor jmen! 9.1

Atributy mohou být pouze pro čtení nebo zapisovatelné. Ve druhém případě je možné atributu přiřadit hodnotu. Atributy modulů jsou zapisovatelné, takže můžete psát "jméno_modulu.odpoved = 42". Zapisovatelné atributy mohou být také smazány pomocí příkazu del. Například "del jméno_modulu.odpoved" odstraní atribut odpoved z objektu jméno_modulu.

Prostory jmen vznikají v různých okamžicích a mají různou délku života. Prostor jmen obsahující interní jména je vytvořen při startu interpretru a není nikdy zrušen. Globální prostor jmen modulu je vytvořen při načtení definice modulu a je obvykle přístupný dokud neukončíte interpretr. Příkazy zadávané interaktivnímu interpretru nebo čtené ze souboru jsou částí modulu nazývaného __main__, takže také mají svůj vlastní globální prostor jmen. (Interní jména zase najdeme v modulu nazývaném __builtin__.)

Lokální prostor jmen funkce je vytvořen při jejím zavolání a je odstraněn při návratu z funkce nebo skončí-li běh funkce neodchycenou výjimkou. Mimo jiné každé rekurzívní volání funkce má svůj vlastní prostor jmen.

Obor jmen je část zdrojového kódu jazyka Python, kde je určitý prostor jmen přímo přístupný. "Přímo přístupný" zde znamená, že jména v něm uvedená mohou být používána přímo, bez použití tečkové notace.

Přestože obory jmen jsou určovány staticky, jsou používány dynamicky. Kdykoli při běhu intrepretru jsou používány přesně tři obory jmen (čili tři prostory jmen jsou přímo přístupné): první obor jmen, který je prohledáván nejprve, obsahuje lokální jména, druhý obor, prohledávaný jako druhý v pořadí, obsahuje globální prostor jmen aktuálního modulu a třetí obor (prohledávaný jako poslední) je prostor interních jmen.

Lokální obor jmen se obvykle odkazuje na lokální jména aktuální funkce. Mimo tělo funkce obsahuje lokální obor jmen stejný prostor jmen jako globální obor, tj. prostor jmen modulu. Definice třídy umisťuje svůj prostor jmen také do lokálního oboru jmen.

Důležité je, že obory jmen jsou určovány staticky: globální obor jmen nějaké funkce definované v nějakém modulu je prostor jmen tohoto modulu, přičemž nezáleží odkud byla funkce zavolána. Na druhou stranu se jména vyhledávají dynamicky při běhu programu -- nicméně, definice jazyka směřuje ke statickému určování jmen při "kompilaci" kódu, takže na dynamické rozlišování jmen nespoléhejte! (Je pravdou, že lokální proměnné jsou již určovány staticky.)

Přiřazení vždy vytváří jména ve vnitřním oboru jmen. Přiřazení nekopírují data -- pouze vytvoří jméno přiřazené určitému objektu. Totéž platí pro odstraňování jmen: příkaz "del x" odstraní odkaz x z prostoru jmen určeném lokálním oborem jmen. Taktéž všechny operace, které vytváří nová jména používají lokální obor jmen - prakticky příkaz import a definice funkce vytvoří odkaz na modul nebo funkce v lokálním oboru. (Příkazem global si můžete vynutit umístění určité proměnné v globálním oboru jmen.)

 
9.3 Třídy na první pohled

Používání tříd zavádí trochu nové syntaxe, tři nové typy objektů a novou sémantiku určitých konstrukcí.

 
9.3.1 Definování tříd

Nejjednodušší tvar definice funkce vypadá podobně jako tento:

class Jméno_třídy:
    <příkaz-1>
    .
    .
    .
    <příkaz-N>

Před používáním třídy musí být spuštěna její definice, podobně jako nejprve musíme spustit definici funkce (konstrukce def) a až poté jí můžeme používat. (Definici třídy můžete dokonce umístit ve větvi konstukce if nebo uvnitř funkce.)

Většinou jsou příkazy uvnitř definice třídy konstrukce pro definice funkcí, ale jsou povoleny i další příkazy -- k této problematice se vrátíme později. Definice funkce uvnitř třídy má charakteristický tvar seznamu argumentů -- opět popsáno dále.

Při spuštění definice třídy je vytvořen nový prostor jmen a je použit jako lokální obor jmen uvnitř "těla" třídy, takže všechna přiřazení lokálním proměnným jdou do nového prostoru jmen. Také definice funkce zde vytvoří jméno nové funkce.

Je-li definice třídy opuštěna normálně (tj. je provedena celá), pak je vytvořen objekt třídy (objekt typu třídy, třídní objekt, třída). Ten je jakýmsi obalem obsahu vytvořeného prostoru jmen. Více se o třídách dozvíte v další sekci. Originální lokální obor jmen (tj. ten, který byl používán před spuštěním definice třídy) je obnoven a objekt typu třída je svázán se jménem třídy předaným v hlavičce definice (Jméno_třídy v tomto případě).

 
9.3.2 Objekty typu třída

Třídní objekty podoporují dva druhy operací - odkazování na atributy a vytváření instancí.

V jazyce Python používají odkazy na atributy standardní syntaxi společnou pro všechny typy objektů: objekt.jméno. Platnými atributy jsou všechna jména, která byla definována v třídním prostoru jmen při vytvoření třídy. Jestliže definice třídy vypadala takto:

class MojeTřída:
    "Jednoduchá třída"
    i = 12345
    def f(self):
        return 'ahoj'

pak MojeTřída.i a MojeTřída.f jsou platnými odkazy na atributy, vracející integer a funkční objekt. Jednotlivým atributům může být také přiřazena nová hodnota. __doc__ je také platným atributem a vrací dokumentační řetězec patřící této třídě: "Jednoduchá třída".

Vytváření instancí používá zápis podobný funkčnímu volání. Dejme tomu, že třídní objekt je funkce, která nepřejímá žádný argument, a vrací novou instanci této třídy. Například (za použití předchozí definice třídy):

x = MojeTřída()

vytvoří novou instanci třídy a přiřadí tento objekt lokální proměnné x.

Vytvořením instance ("zavoláním" objektu třídy) získáme prázdný objekt. Mnoho tříd ale potřebuje vytvořit objekty v určitém počátečním stavu. Proto může třída definovat speciální metodu pojmenovanou __init__():

    def __init__(self):
        self.data = []

Definuje-li třída metodu __init__(), pak při vytvoření instance je tato metoda zavolána pro nově vzniklou instance. Novou ziniciovanou instanci můžeme získat pomocí výrazu:

x = MojeTřída()

Pro větší flexibilitu může metoda __init__() mít i argumenty. V tomto případě budou argumenty dodané třídě při vytvoření instance předány metodě __init__(). Například

>>> class Complex:
...     def __init__(self, realpart, imagpart):
...         self.r = realpart
...         self.i = imagpart
... 
>>> x = Complex(3.0, -4.5)
>>> x.r, x.i
(3.0, -4.5)

 
9.3.3 Instančí objekty

Co nyní můžeme s instančním objektem dělat? Jedinou operací, kterou tyto objekty podporují, je odkazování na atributy. Python rozlišuje dva druhy atributů.

První z nich budeme nazývat datové atributy. Ty odpovídají "instančním proměnným" ve Smalltalku a "datovým členům" v C++. Datové atributy, podobně jako lokální proměnné, nemusíte deklarovat -- vzniknou při prvním přiřazení hodnoty. Například, je-li x instance třídy MojeTřída vytvořené výše, následující kus kódu vytiskne hodnotu 16:

x.counter = 1
while x.counter < 10:
    x.counter = x.counter * 2
print x.counter
del x.counter

Druhým typem atributů jsou metody. Metoda je funkce, která určitým způsobem "patří" k objektu. (V Pythonu neplatí termín metoda pouze pro instance tříd, ale i pro jiné typy objektů. Například seznamy nají metody nazvané append, insert, remove, sort atd. V dalším výkladu budeme používat termín metoda výhradně u instancí tříd, nebude-li řečeno jinak.)

Správná jména metod instance závisí na její tříde. Všechny atributy třídy, které jsou uživatelsky definovanými funkcemi, určují odpovídající metody instancí této třídy. Takže v našem případě x.f je platným odkazem na metodu, protože MojeTřída.f je funkce, ale x.i není, protože MojeTřída.i funkcí není. x.f ale není to samé co MojeTřída.f -- je to  objekt metody (metoda), ne funkce.

 
9.3.4 Metody

Většinou jsou metody volány přímo:

x.f()

V našem případě tento kód vrátí řetězec 'ahoj'. Metodu ale mnohdy není nutné volat přímo: x.f je objekt metody a může být uchován a zavolán později. Například:

xf = x.f
while 1:
    print xf()

bude neustále tisknout "ahoj".

Co se stane, když je metoda zavolána? Možná jste si všimli, že metoda x.f() byla volána bez argumentu, i když definice metody f argument specifikuje. Co je za argument dosazeno? Python přece vyvolá výjimku, když funkce požaduje argument a je volána bez něj -- i když argument není použit...

Možná vás napadla odpověď: to co rozlišuje metody od jiných atributů je právě automatické dosazování instance za první argument metody. V našem příkladě je volání x.f() ekvivalentní MojeTřída.f(x). Obecně platí, že volání metody se seznamem n argumentů je stejné jako volání odpovídající funkce se seznamem argumentů získaným vložením instance před první argument.

Jestliže jste ještě nepochopili, jak metody pracují, podívejte se na princip jejich implementace: je-li odkazováno na atribut instance, který však není v této instanci nalezen, je prohledána jeho třída. Jestliže jméno znamená platný atribut třídy a zároveň jde o funkci, je vytvořena metoda složením objektů instance a funkce. Při zavolání metody dojde k jejímu "rozložení" zpět na funkční objekt a instanci, načež se zavolá funkce, které se předá samotná instance. Je-li metoda navíc zavolána se seznamem argumentů, je rovněž rozložena na funkci a instanci. Následně je vytvořen nový seznam argumentů z instance a originálního seznamu argumentů. Poté je funkce zavolána s tímto novým seznamem argumentů.

 
9.4 Více ...

Datové atributy přepíší metody se stejným jménem. Abyste se vyvarovali konfliktům mezi jednotlivými jmény, které mohou způsobit těžko dohledatelné chyby ve velkých programech, je lepší použít určitý druh konvencí, které minimalizují možnost střetu jmen. Tyto konvence zahrnují psaní jmen metod s velkým písmenem, před názvy datových atributů vkládat krátký jednoznačný řetězec (třeba pouhé podtržítkou) nebo používání sloves pro metody a podstatných jmen pro datové atributy.

Datové atributy mohou být používány metodami stejně jako obyčejnými uživateli ("klienty") objektu. Jinými slovy - třídy není možné použít k implementaci čistě abstraktních datových typů. Žádná třída v Pythonu si nemůže vynutit skrytí svých datových struktur. (Na druhé straně, implementace rozšíření jazyka Pythonu napsaná v C mohou kompletně skrýt implementační detaily a kontrolovat přístup k objektu, je-li to nutné.)

Klienti by měli používat datové atributy s opatrností -- klient může porušit vnitřní konzistenci instance, kterou jinak zajišťují metody. Klienti však mohou do instancí přidávat své vlastní datové atributy bez porušení konzistence za předpokladu, že se vyhnou konfliktům s jinými jmény -- opět na tomto místě může pomoci určitá konvence při pojmenovávání atributů.

Neexistuje žádná zkratka pro odkazování datových atributů (nebo metod) z jiné metody. Myslím, že toto opatření zároveň zvyšuje čitelnost metod: při pohledu na kód není šance splést si lokální a instanční proměnné.

Podle konvencí je první argument metody nejčastěji nazýván self. Není to nic víc než konvence -- jméno self nemá absolutně žádný speciální význam. (Kdykoli, když porušíte tuto konvenci, se váš kód stane hůře čitelným pro ostatní programátory a rovněž je možné, že různé prohlížeče kódu, které na této konvenci závisí, odmítnout váš kód zobrazit.)

Každá funkce, která je atributem třídy, znamená pro její instance metodu. Přitom není nutné, aby tato funkce byla přímo textově vložena v definici třídy, je možné přiřadit funkci nějaké lokální proměnné uvnitř třídy:

# Funkce definovaná mimo třídu
def f1(self, x, y):
    return min(x, x+y)

class C:
    f = f1
    def g(self):
        return 'ahoj'
    h = g

Nyní f, g a h jsou všechno atributy třídy C, které odkazují na objekty typu funkce -- všechny jsou zároveň metodami instancí třídy C -- h je totéž co g a f je totéž co f1. Tyto praktiky ale vždy dokonale zmatou čtenáře tohoto kódu.

Metody mohou volat další metody za použití atributů argumentu self:

class Bagl:
    def __init__(self):
        self.data = []
    def pridej(self, x):
        self.data.append(x)
    def pridej_dvakrat(self, x):
        self.pridej(x)
        self.pridej(x)

Metody mohou používat globální jména stejným způsobem jako obyčejné funkce. Globální obor jmen asociovaný s metodou je prostor jmen modulu obsahujícího definici třídy. (Třída samotná není nikdy použita jako globální obor jmen!) Nevíte-li o důvodu, proč používat globální data v metodách, pak zde je jeden příklad za všechny: moduly importované do globálního oboru jmen mohou používat obyčejné funkce modulu úplně stejným způsobem jako metody naší třídy. Většinou jsou také třídy definovány v globálním prostoru jmen a v další sekci si povíme důvod, proč se metoda někdy potřebuje odkazovat na svojí vlastní třídu!

 
9.5 Dědičnost

Samotné třídy by nám nebyly příliš užitečné bez vlastnosti nazývané dědičnost. Syntaxe odvozené třídy vypadá podobně jako:

class OdvozenáTřída(ZákladníTřída):
    <příkaz-1>
    .
    .
    .
    <příkaz-N>

Jméno ZákladníTřída musí být definováno v oboru jmen obsahujícím definici odvozené třídy. Kromě jména základní třídy je také možné použít libovolný výraz. To je užitečné obzvlášť, když je základní třída definována v jiném modulu.

class OdvozenáTřída(jméno_modulu.ZákladníTřída):

Spuštění definice odvozené třídy proběhne stejně jako u rodičovské třídy. Při vytvoření třídy je zapamatována její rodičovská třída, které je použita pro vyhodnocení odkazů na atributy -- jestliže není atribut nalezen v této třídě, je hledán v rodičovské třídě. Toto pravidlo je aplikováno rekurzivně, jestliže rodičovská třída je opět odvozena od jiné třídy.

Na vytvoření instance odvozené třídy není nic zvláštního, OdvozenáTřída() normálně vytvoří novou instanci třídy. Odkazy na metody jsou vyhodnocovány následovně: odpovídající funkční objekt se hledá nejprve v odvozené třídě, není-li nalezen, začnou se prohledávat rodičovské třídy. Nakonec se provede zabalení funkce a její instance do objektu metody. Tuto metodu můžeme samozřejmě volat jako jakoukoli jinou metodu.

Odvozené třídy mohou přepsat metody jejich rodičovských tříd. Jelikož Python nerozlišuje mezi klienty objektu a metodami objektu samého, pak, volají-li metodu jiné metody téhož objektu, je ve skutečnosti volána nově definovaná metoda v potomkovi. Metody rodičovské třídy tudíž ve skutečnosti volají metody odvozené třídy. (Pro programátory v C++: všechny metody v Python jsou virtuální.)

Metoda, které předefinovává metodu svého předka, většinou pouze rozšiřuje chování předka. Proto existuje jednoduchá cesta, jak vykonat metodu předka přímo, prostě zavolejte "ZákladníTřída.metoda(self, argumenty)". Tento postup se také může hodit i klientům objektu. (Pracuje však pouze, když je rodičovská třída definována nebo importována přímo v globálním oboru jmen. Jinak musíme uvést plně kvalifikované jméno třídy: "jméno_modulu.ZákladníTřída.metoda(self, argumenty)")

 
9.5.1 Vícenásobná dědičnost

Python podporuje i vícenásobnou dědičnost. Definice třídy s více rodičovskými třídami vypadá následovně:

class OdvozenáTřída(Rodič1, Rodič2, Rodič3):
    <příkaz-1>
    .
    .
    .
    <příkaz-N>

Jediné pravidlo nutné k pochopení tohoto principu je pravidlo pro vyhledávání atributů. Zní "první strom, zleva doprava." Takže jestliže atribut není nalezen ve třídě OdvozenáTřída, je rekurzivně prohledávána třída Rodič1 a její rodiče, pak vyhledávání pokračuje třídou Rodič2 a jejími předky a teprve, pokud ani zde nebyl atribut nalezen, je prohledávána třída Rodič3 a její předci.

(Pro někoho by bylo přijatelnější prohledávání tříd Rodič2 a Rodič3 před předky třídy Rodič1. Vypadá to přirozeněji, jenže bychom potřebovali vědět, je-li daný atribut třídy Rodič1 definován ve tříde Rodič1 nebo v nějakém jejím předkovi. Jestliže atribut by byl definován v nějakém předkovi, prohledávala by se nejprve třída Rodič2, díky čemuž by mohlo dojít ke konfliktům jmen. Pravidlo "první strom" nedělá rozdíly mezi vlastními nebo zděděnými atributy třídy Rodič1.)

Nadměrné používání vícenásobné dědičnosti se dříve či později stane noční můrou každého programátora. Při používání vícenásobné dědičnosti platí více než kde jinde nutnost striktního dodržování jistých konvencí pro vyvarování se konfliktům jednotlivých jmen. Známým problémem je třída odvozená za dvou tříd, které mají společného předka. Je snadné si představit, co se v tomto případě stane (instance má jedinou kopii "instančních proměnných" používanou společným předkem).

 
9.6 Soukromé proměnné

Python obsahuje omezenou podporu pro soukromé atributy. Každý identifikátor ve tvaru __spam (minimálně první dva a nejvýše jeden poslední znak jsou podtržítka) je nahrazen názvem _jménotřídy__spam, kde jménotřídy je jméno aktuální třídy bez ukončujících podtržítek. Toto nahrazení je použito všude nezávisle na pozici identifikátoru, takže může být použit pro soukromé třídní a instanční proměnné, metody a také pro uložení instančních proměnných této třídy v instancích jiných tříd. Je-li nově vytvořené jméno delší než 255 znaků, bude zkráceno. Mimo třídu, stejně jako je-li jméno třídy tvořeno samými potržítky, k žádnému nahrazování nedojde.

Nahrazování jmen je určeno pro třídy, u nichž programátor chce definovat "soukromé" instanční proměnné nebo metody, aniž by se musel zajímat o jména instančních proměnných v odvozených třídách. Pravidla pro nahrazování jmen jsou navržena pro vyvarování se problémům, které mohou způsobit konflikty jmen. Pořád je ale možné "soukromou" proměnnou modifikovat pomocí jména _jménotřídy__spam. To může být užitečné ve speciálních případech, například při ladění kódu. Toto je zároveň jediný důvod, proč jsou "soukromé" proměnné veřejně přístupné (Odvození třídy se stejným jménem jako má rodičovská třída také umožní používání soukromých proměnných rodičovské třídy.)

Nezapomeňte, že kód předaný příkazu exec a funkcím eval() a evalfile() nepovažuje jméno volající třídy za jméno aktuální třídy. S tímto problémem se potkáme také při používání příkazu global ve spojení s těmito funkcemi -- jak global tak nahrazování jmen se uplatní pouze u kódu, který je již zkompilován. Stejně tak nebude náhrada jmen pracovat s funkcemi getattr(), setattr() a delattr() nebo při přímém používání atributu __dict__.

Zde je příklad třídy, která implemetuje svoje vlastní metody __getattr__() a __setattr__() a všechny atributy ukládá v soukromé proměnné způsobem, který funguje na všech verzích jazyka Python včetně těch, ve kterých ještě nahrazování jmen nebylo implementováno:

class VirtualAttributes:
    __vdict = None
    __vdict_name = locals().keys()[0]
     
    def __init__(self):
        self.__dict__[self.__vdict_name] = {}
    
    def __getattr__(self, name):
        return self.__vdict[name]
    
    def __setattr__(self, name, value):
        self.__vdict[name] = value

 
9.7 Pár slov navíc

Někdy je dobré mít datový typ podobný pascalovskému záznamu nebo strukturám jazyka C. Tyto typy obsahují několik datových prvků a přistupuje se k nim pomocí jejich jmen. Tento typ elegantně získáme použitím třídy s prázdnou definicí:

class Zamestnanec:
    pass

honza = Zamestnanec() # Vytvoří prázdný záznam o zaměstnanci

# Vyplní jednotlivé položky záznamu
honza.jmeno = 'Honza Švec'
honza.skupina = 'PyCZ'
honza.plat = 100000

Kód, který předpokládá použití určitého abstraktního datového typu, často může používat i třídu, která emuluje metody daného datového typu. Například máte-li funkci, která formátuje data přečtená ze souborového objektu, můžete definovat vlastní třídu s metodami read() a readline() a následně předat funkci její instanci namísto souborového objektu.

Objekt metody svázané s instancí má také atributy: m.im_self je instance, se kterou je metoda svázána, a m.im_func je funkční objekt odpovídající metodě.

 
9.7.1 Výjimky mohou být třídy

Uživatelsky definované výjimky již dávno nemusí být identifikovány pouze řetězci -- stejně dobře mohou posloužit i třídy. Používáním tohoto mechanismu můžete vytvořit rozsáhlou hiearchii výjimek.

Je možné použít dva tvary příkazu raise:

raise třída, instance

raise instance

V prním případě, instance musí být instance třídy třída nebo třídy od ní odvozené. Druhý tvar je zkráceninou zápisu:

raise instance.__class__, instance

Větve except mohou uvádět třídy stejným způsobem jako řetězce. Třída použitá ve větvi except odpovídá výjimce, jde-li u tutéž třídu nebo o jejího předka (odvozená třída tudíž svému předkovi neodpovídá!). Následující kód vytiskne B, C, D přesně v tomto pořadí:

class B:
    pass
class C(B):
    pass
class D(C):
    pass

for c in [B, C, D]:
    try:
        raise c()
    except D:
        print "D"
    except C:
        print "C"
    except B:
        print "B"

Když bychom větve except uvedli v opačném pořadí ("except B" první), vytisklo by se B, B, B, protože vždy je spuštěna pouze první odpovídající větev except (tedy "except B").

Při vypsání chybové zprávy pro neobslouženou výjimku, která je třídou, je nejprve vytisknuto jméno třídy, pak dvojtečka, mezera a nakonec instance zkonvertovaná na řetězec za použítí interní funkce str().



Footnotes

... jmen!9.1
S jednou výjimkou. Modulové objekty mají tajný atribut určený pouze pro čtení a nazývaný __dict__, což je slovník použitý k implementování prostoru jmen tohoto modulu. Jméno __dict__ je jméno atributu, ale ne globální jméno. Jeho používáním porušíte těsnou vazbu mezi atributy a globálním prostorem jmen. Atribut __dict__ je vyhrazen pro nástroje typu post-mortem debugger apod.
See About this document... for information on suggesting changes.