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í.
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ů.)
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):
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
.
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
slovem — LOCAL
.
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 $