Lokální proměnné #

Už umíš definovat vlastní funkce. Zbývá ale ještě dovysvětlit, jak v nich fungují proměnné.

Funkce může používat proměnné „zvnějšku“. Následující program přiřadí do proměnné pi a všechny další funkce mají k pi přístup:

pi = 3.1415926

def obsah_kruhu(polomer):
    return pi * polomer ** 2

print(obsah_kruhu(100))

Jinak je tomu ale v případě, kdy proměnnou nastavíš uvnitř funkce.

Všechny parametry a všechny proměnné, do kterých funkce přiřazuje, jsou úplně nové proměnné, které nemají nic společného s tím, co je „venku“ kolem funkce.

Těmto proměnným se říká lokální proměnné (angl. local variables), protože existují jen místně, v rámci volání jedné jediné funkce.

Proměnné, které nejsou lokální, jsou globální – ty existují v celém programu.

Pro příklad:

def nastav_x(hodnota):
    x = hodnota  # Přiřazení do lokální proměnné!

nastav_x(40)
print('x =', x)

Program skončí s chybou! Funkce nastav_x si hraje na vlastním písečku; proměnná x je jen pro ni. Když funkce nastav_x skončí, proměnná x přestane existovat.

Skrývání detailů #

Podobně skončí s chybou i složitější program:

def zamen(slovo, pozice, novy_znak):
    """V daném slově zamění znak na dané pozici za daný nový znak"""
    zacatek = slovo[:pozice]
    konec = slovo[pozice + 1:]
    nove_slovo = zacatek + novy_znak + konec
    return nove_slovo

print(zamen('kočka', 1, 'a'))
print(zamen('kačka', 2, 'p'))

print(zacatek)  # NameError

Funkci zamen jsi napsal/a proto, abys nemusel/a pořád opakovat detaily záměny písmenka. Jakmile je jednou nadefinovaná, stačí ji zavolat. Důležité jsou jen jméno funkce, parametry a návratová hodnota; na detaily kódu uvnitř můžeš zapomenout. A to i díky lokálním proměnným, které detaily ve vnitřku funkce trochu líp izolují od zbytku programu.

Ještě lépe je to vidět u funkcí, které jsi nenapsal/a sám/sama. Jak divné by bylo, kdyby po každém zavolání print byla najednou nastavená proměnná i, kterou print náhodou používá při procházení svých parametrů!

Přiřazení #

To, co dělá lokální proměnnou, je přiřazení. Porovnej nastav_x s příkladem na obsah_kruhu výše: rozdíl mezi pi a x je v tom, že do x se v rámci funkce přiřazuje.

Co je to přiřazení? Všechno, co nastavuje nějakou proměnnou. Například:

  • Klasika je přiřazovat pomocí =, např. a = 3.
  • Parametry funkce: funkce def nastav_x(hodnota) přiřadí do hodnota,
  • Cyklus for x in ...: přiřazuje do proměnné x.
  • Pro úplnost, příkazy def x(...):, import x a from ... import x taky přiřazují do x – ale ve funkcích se moc nepoužívají.

A další

K těmto materiálům se možná budeš vracet, tak pro úplnost přidám další způsoby, které postupně poznáš. Není jich mnoho:

  • Příkazy with ... as x, del x, except ... as x přiřazují do x.
  • Přiřazují i speciální přiřazovací operátory jako +=, *=, :=.

Zakrývání jména #

Jak to funguje, když ve funkci přiřadíš do proměnné, která existuje i globálně? Pak tu máme problém.

Vytvoří se úplně nová lokální proměnná, která má stejné jméno jako ta globální. Jméno označuje lokální proměnnou, a ta globální pak „není vidět“.

Tento příklad tedy nebude fungovat tak, jak se zdá:

x = 0

def nastav_x(hodnota):
    x = hodnota  # Přiřazení do lokální proměnné!
    print('Ve funkci nastav_x: x =', x)

nastav_x(40)
print('Venku: x =', x)

V tomto programu existují dvě proměnné jménem x. Jedna je globální. Jedna je lokální pro funkci nastav_x. Jmenují se stejně, ale jsou to dvě různé proměnné.

Lokální nebo globální? #

Pojďme si to ukázat. Než spustíš tenhle program, zkus předpovědět, co bude dělat. Pak ho pusť, a pokud dělal něco jiného, zkus vysvětlit proč. Pozor na chytáky!

from math import pi
obsah = 0
a = 30

def obsah_elipsy(a, b):
    obsah = pi * a * b  # Přiřazení do `obsah`
    a = a + 3  # Přiřazení do `a`
    return obsah

print(obsah_elipsy(a, 20))
print(obsah)
print(a)

Zkus odpovědět na tyto otázky:

  • Je proměnná pi lokální, nebo globální?
  • Je proměnná obsah lokální, nebo globální?
  • Je proměnná a lokální, nebo globální?
  • Je proměnná b lokální, nebo globální?
  • Je proměnná obsah_elipsy lokální, nebo globální?

Řešení

Rada na závěr #

Pravidla pro lokální proměnné jsou pro začátečníky jednou z nejzvláštnějších věcí v Pythonu. Jsou ale přínosná – umožňují některé užitečné techniky, např. rekurzi.

Jestli ti to celé připadá složité, dá se tomu zatím vyhnout dodržováním jednoho pravidla: nepřiřazuj ve funkcích do proměnných, které existují i vně funkce. (Parametr funkce se počítá jako přiřazení.)