Níže uvedený text pochází z prvního vydání. Nad tímto textem se nachází aktuální stav po revizi sm>řující k druhému vydání.

Prostory jmen

Úvod

Už slyším, jak se ptáte… Co to je ten prostor jmen (namespace)? No, dá se to t>žko vysv>tlit. Ne proto, že by to bylo n>jak zvlášť komplikované, ale spíš proto, že se k tomu každý jazyk staví trochu jinak. Samotný koncept je docela přímočarý. Prostor jmen je prostor nebo oblast uvnitř programu, kde je jméno (prom>nné, třídy, atd.) platné.

Dřív>jší programovací jazyky (jako třeba BASIC) pracovaly pouze s globálními prom>nnými, to znamená s takovými prom>nnými, které byly vid>t z celého programu — dokonce uvnitř funkcí. To činilo udržovatelnost programů velmi obtížnou, protože pro každý kousek programu bylo velmi snadné zm>nit n>jakou prom>nnou, aniž by se to ostatní části programu n>jak dozv>d>ly. Tomuto jevu se říká vedlejší efekt. Nov>jší jazyky (včetn> moderních verzí jazyka BASIC) tento problém obcházejí zavedením prostorů jmen. (Jazyk C++ jde v tomto sm>ru do extrému tím, že umožňuje programátorovi vytvořit svůj vlastní prostor jmen kdekoliv uvnitř programu. To ocení zvlášt> tvůrci knihoven, kteří cht>jí dosáhnout jednoznačnosti jmen svých funkcí i v případ>, kdy se současn> použijí knihovny jiných tvůrců.)

Jak to řeší Python?

V systému Python vytváří každý modul svůj vlastní prostor jmen. Pokud chceme používat jména jeho částí, musíme jim buď předřadit jméno modulu, nebo musíme explicitn> importovat požadovaná jména dovniř prostoru jmen našeho modulu. Není to pro nás nic nového. Už jsme to d>lali při práci s moduly sys a string. V určitém smyslu vytváří svůj prostor jmen i definice třídy. Takže pokud chceme zpřístupnit metodu nebo vlastnost třídy, musíme nejdříve použít jméno instance nebo třídy.

V Pythonu existují jen 3 prostory jmen (nebo rozsahy platnosti — scopes):

  1. Lokální rozsah — jména definovaná uvnitř funkce nebo metody.
  2. Rozsah v rámci modulu — jména definovaná uvnitř souboru modulu.
  3. Zabudovaná jména — jména definovaná uvnitř samotného systému Python, která jsou přístupná vždy.

No dobrá. Ale jak to vše dáme dohromady, když prom>nné v různých prostorech jmen mají stejné jméno? A nebo, jak se odkazujeme na jméno, které se nenachází v aktuálním prostoru jmen? Podívejme se nejdříve na první případ: Pokud se funkce odvolává na prom>nnou nazvanou X a uvnitř funkce existuje n>jaká prom>nná X (tj. uvnitř prostoru s lokálními prom>nnými), pak to bude práv> tato lokální prom>nná, kterou Python uvidí a použije. Je v>cí programátora, aby se vyhnul střetům jmen, kdy má n>jaká lokální prom>nná stejné jméno jako prom>nná modulu a kdy bychom mohli chtít zpřístupnit ob> najednou. Existence lokální prom>nné v takovém případ> maskuje existenci globální prom>nné.

Obecn> bychom m>li globální prom>nné používat co nejmén>. Obvykle bývá lepší, když b>žnou, lokální prom>nnou předáváme jako parametr volané funkce a vrací se nám s modifikovaným obsahem.

Poznámka překladatele ke globálním prom>nným: Z pohledu začátečníka se může zdát používání globálních prom>nných velmi výhodné. Jednoduše přece uvedeme jméno prom>nné, které je známé ve všech místech programu! V čem je problém? Postupn> zjistíte, že t>ch problémů může být hned n>kolik. Zdánlivá jednoduchost může pozd>ji v>ci zkomplikovat:

Druhý případ, kdy se odkazujeme na jméno, které se nenachází mezi lokálními, se řeší následujícím způsobem: Funkce prohlédne svůj lokální prostor. Pokud zde požadované jméno nenalezne, hledá v prostoru modulu. A pokud není nalezeno ani zde, hledá se v prostoru zabudovaných jmen (builtin scope). Jediná nepříjemnost nastane v situaci, kdy chceme přiřadit hodnotu externí prom>nné. Při normálním postupu by vznikla nová prom>nná tohoto jména, ale tomu se chceme vyhnout. Takže aby se nevytvořila lokální prom>nná daného jména, musíme určit, že se jedná o jméno globální.

Vše si ukážeme v akci na následujícím příkladu (jde o čist> ilustrační příklad):

# Prom>nné na úrovni modulu.
W = 5
Y = 3
 
# Parametry se chovají jako prom>nné náležející funkci. Takže X patří
# do lokálního prostoru.
def spam(X):
    
   # Funkci oznámíme, že má W hledat na úrovni modulu a nevytvářet svou 
   # prom>nnou W.
   global W
   
   Z = X*2 # Nová prom>nná Z je vytvořena jako lokální.
   W = X+5 # Práce s W na úrovni modulu -- viz výše.

   if Z > W:
      # pow je jméno 'zabudované' funkce.
      print pow(Z, W)
      return Z
   else:
      return Y # Lokální Y neexistuje, takže se použije globální.

Pokud importujeme modul, jako je například sys, stane se jméno sys lokáln> dostupným jménem. Poté můžeme jména uvnitř prostoru jmen modulu sys zpřístupnit použitím takzvaného kvalifikovaného jména, jak jsme si ukázali dříve. (Kvalifikované jméno se od holého liší tím, že holému jménu předřadíme takzvaný kvalifikátor, který má podobu dalšího jména, vhodn> spojeného s původním holým jménem. V jazyce Python se ob> části odd>lují tečkou. Například v jazyce C++ se odd>lují dv>ma dvojtečkami.)

Pokud napíšeme

from sys import exit

pak v lokálním prostoru jmen zpřístupníme pouze funkci exit. Nemůžeme použít žádné jiné jméno z modulu sys a dokonce ani samotné jméno modulu sys.

Ješt> v jazyce BASIC...

BASIC volí ve srovnání z jazykem Python opačný přístup. Všechny vytvořené prom>nné se automaticky stávají globálními (aby byla zachována kompatibilita, tedy slučitelnost, s programy psanými pro starší verze jazyka BASIC), ale programátor může vytvářet i prom>nné, které jsou lokální uvnitř funkcí, jejich označením klíčovým slovemLOCAL.

Tcl

Asi si mohu dovolit tvrdit, že v Tcl neexistuje žádný mechanismus pro přístup k různým úrovním viditelnosti jmen. Důvodem je asi zvláštní způsob, jakým Tcl program provádí. Všechny prom>nné se v každém případ> jeví jako lokální vzhledem k jejich nejbližšímu okolí — prom>nné na úrovni souboru jsou viditelné pouze pro příkazy uvnitř stejného souboru a prom>nné procedur jsou viditelné pouze uvnitř procedur. Komunikaci mezi t>mito prostory jmen můžeme zajistit pouze předáváním hodnot v podob> parametrů, při volání zmín>ných procedur.


Pokud vás napadne, co by se dalo na překladu této kapitoly vylepšit, zašlete e-mail odklepnutím Tím budou do dopisu automaticky vloženy informace o tomto HTML dokumentu.

$Id: cztutname.html,v 1.6 2005/09/15 18:24:08 petr Exp $