[Tutor PyCZ] Globalni, lokalni a volne promenno (bylo Dalsi problem s Livewires)

Tomáš Bělonožník rebelme na gmail.com
Čtvrtek Březen 2 00:19:07 CET 2006


Díky za všeosvětlující vysvětlení. Teď je jasno :), jsem si to
vytisknul a pripich na polystyren za monitorem, kdybych něco zas
zapomněl tak to mít aspoň po ruce.

2006/3/1, Petr Prikryl <PrikrylP na skil.cz>:
> geon
> > Tomáš Bělonožník napsal(a):
> > > [...]
> > > def posunHrace():
> > >     stisky = keys_pressed()
> > >     if "2" in stisky:
> > >         yh = yh - 10
> > >         move_to(Hrac_telo, xh, yh)
> > >         return yh
> > >
> > > [...] Hází mi to ale chybu "local variable 'yh'
> > > referenced before assignment". Chápu to
> > > tak, že jsem proměnnou yh zmínil ještě předtím,
> > > než jsem jí přiřadil nějakou hodnotu. Ale proč
> > > si tu hodnotu nevezme sám z vyšších pater
> > > programu, jako to udělal, když řádek move_to vypadal
> > > "move_to(Hrac_telo, xh, yh-10)".
>
> > [...] Trocha teorie ode mne: některé proměnné
> > skutečně funkce dokáže brát zezhora - zde třeba Hrac_telo
> > nebo tvůj výše uváděný move_to(Hrac_telo, xh, yh-10).
> > Jsou to ale vzdy jen ty proměnné, které se ve funkci
> > nemění - jsou tam jen jakoby read-only. Proto ti to
> > házelo tu chybu, protože jsi chtěl změnit read-only
> > proměnnou.
>
> Pokud ve funkci použiji proměnnou a nesnažím
> se do ní přiřazovat, jde o takzvanou volnou proměnnou
> (free variable). Volnou se nazývá proto, protože
> v bloku kódu neexistuje pevná vazba mezi jménem
> 'x' a konkrétním místem, kde je hodnota uložena.
> V okamžiku odkazu se teprve poloha "ve vyšších patrech"
> bude zjišťovat.
>
> Pokud do proměnné něco přiřadím, stává se lokální
> proměnnou v daném bloku kódu. Vyytváří se pevná
> vazba z mého lokálního prostoru. Už nemůžeme hovořit
> o volné proměnné (tj. o proměnné definované někde
> ve vyšších patrech). Pevná vazba na lokální prostor
> se vytváří i tehdy, když se do této proměnné
> přiřazuje až později (ve stejném bloku), než když
> se z ní čte. Příklad:
>
> soubor a.py
> =====================================
> x = 10
>
> def funkce1():
>     print x
>
> def funkce2():
>     return x
>
> print x            # (1)
> funkce1()          # (2)
> print funkce2()    # (3)
> =====================================
>
> Příkaz "print x" na řádku (1) vytiskne
> podle očekávání hodnotu 10. Jde o proměnnou
> definovanou na stejné úrovni.
>
> Na řádku (2) voláme funkce1() a ta se
> v příkazu "print x" tiskne proměnou, která
> je definována na "vyšší úrovni". Jde ale
> o volnou proměnnou, která se postupně hledá
> v nadřízených lokálních prostorech (zde
> žádné nemáme) a nakonec v prostoru globálním.
>
> Na řádku (3) tiskneme výsledek, který získáváme
> voláním funkce2(). V jejím těle se pouze vrací
> hodnota volné proměnné x. Jde o podobný případ,
> jako u funkce1(). Hodnota proměnné x se pouze
> zpracuje jiným způsobem.
>
> Zkuste ale tohle:
>
> soubor c.py
> =====================================
> x = 10
>
> def funkce3():
>     x = x + 1
>     print x
>
> funkce3()
> =====================================
>
> Při pokusu o spuštění se ukáže toto...
>
> C:\tmp>python c.py
> Traceback (most recent call last):
>   File "c.py", line 7, in ?
>     funkce3()
>   File "c.py", line 4, in funkce3
>     x = x + 1
> UnboundLocalError: local variable 'x' referenced before assignment
>
> Jak už bylo uvedeno výše, přiřazení "x = x + 1"
> způsobí, že funkce3 už o proměnné x chce uvažovat
> jako o lokální proměnné. Jenže tato lokální proměnná
> je použita na pravé straně přiřazení a zatím jí
> nebyla přiřazena žádná hodnota, tj. "proveden
> odkaz na lokální proměnnou 'x', které dosud nebylo
> nic přiřazeno". Ona vlastně proměnná x zatím
> neexistuje a chceme ji vytvořit a přiřadit
> jí její neexistující hodnotu zvětšenou o jedničku.
>
> Ve stejném bloku kódu označuje jedno jméno
> jen jednu proměnnou. Python nedovolí, abychom
> se na tuto proměnnou dívali chvíli jako na volnou
> proměnnou (vytvořenou ve vyšších patrech) a o něco
> později jako na lokální proměnnou. Z tohoto důvodu
> selže i následující příklad:
>
> soubor d.py
> =====================================
> x = 10
>
> def funkce4():
>     print x
>     x = x + 1
>
> funkce4()
> =====================================
>
> C:\tmp\a>python d.py
> Traceback (most recent call last):
>   File "d.py", line 7, in ?
>     funkce4()
>   File "d.py", line 4, in funkce4
>     print x
> UnboundLocalError: local variable 'x' referenced before assignment
>
> Tentokrát selže už příkaz "print x", který
> ve funkce1() normálně fungoval. Tehdy jsme se
> ale na x dívali jako na volnou proměnnou
> (definovanou jinde). Jenže příkaz "x = x + 1"
> ve funkce4() způsobí, že x nemůže být volnou
> proměnnou. V okamžiku definice funkce4() už se
> rozhodne o tom, že x bude lokální proměnná
> a nikdy jinak. Za těchto okolností se na příkaz
> "print x" pohlíží jako na pokus zobrazit obsah
> dosud neexistující proměnné.
>
> Pokud by Python nebyl tak přísný a měnil
> by charakter proměnné z volné na lokální
> až podle potřeby, mohlo by to fungovat,
> ale pro člověka by se zdrojový text stával
> nepřehledným a v komplikovanějších případech
> by to mohlo vést k těžko odhalitelným chybám.
> Už jen v případě "x = x + 1" bychom vlastně
> nemohli říci, co ten příkaz dělá, protože
> bychom neměli jistotu, že se na obou stranách
> přiřazení pracuje se stejnou proměnnou x.
>
> pepr
> _______________________________________________
> Tutor mailing list
> Tutor na py.cz
> http://www.py.cz/mailman/listinfo/tutor
>


--
"Any fool who would die for honor is better off dead." - Cabal Patriarch
"I don't know what the next World War will be fought with, but the
World War after that will be fought with sticks and stones." - Albert
Einstein


Další informace o konferenci Tutor