1 | ||
Editor: geon
Time: 2006/05/25 15:57:28 GMT+0 |
||
Note: oprava chyb |
changed: - Vysvětlení 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. Vytváří 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() Po spuštění dostáváme:: 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. Možná řešení Jako mustr si vemme:: # soubor c.py x = 10 def funkce3(): x = x + 1 print x funkce3() Důsledná lokalizace To je asi nejméně častý případ. Proměnná x má být ve funkci lokální a po opuštění funkce zaniká (tam venku ji nepotřebujeme). V tomto případě je to obzvláště nesmyslné, ale někdy to tak může být myšleno:: def funkce3(): x=10 x = x + 1 print x Oškivá globalizace Globalizováním proměnné x ve funkci ji spojíme s proměnnou x definovanou v hlavní části programu. Je to ale nečisté a nedoporučované řešení:: def funkce3(): global x x = x + 1 print x Předáváním a vracením proměnné Proměnnou pokaždé do funkce předáme a na konci ji zase vrátíme:: x = 10 def funkce3(x): x = x + 1 print x return x x = funkce3(x) Použitím měnitelných typů Seznamy, třídy a další se mohou v těchto případěch uplatnit jako nosiče proměnných, které se dají měnit všude:: x = [10] def funkce3(): x[0] = x[0] + 1 print x[0] funkce3()
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. Vytváří 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()
Po spuštění dostáváme:
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.
Jako mustr si vemme:
# soubor c.py x = 10 def funkce3(): x = x + 1 print x funkce3()
To je asi nejméně častý případ. Proměnná x má být ve funkci lokální a po opuštění funkce zaniká (tam venku ji nepotřebujeme). V tomto případě je to obzvláště nesmyslné, ale někdy to tak může být myšleno:
def funkce3(): x=10 x = x + 1 print x
Globalizováním proměnné x ve funkci ji spojíme s proměnnou x definovanou v hlavní části programu. Je to ale nečisté a nedoporučované řešení:
def funkce3(): global x x = x + 1 print x
Proměnnou pokaždé do funkce předáme a na konci ji zase vrátíme:
x = 10 def funkce3(x): x = x + 1 print x return x x = funkce3(x)
Seznamy, třídy a další se mohou v těchto případěch uplatnit jako nosiče proměnných, které se dají měnit všude:
x = [10] def funkce3(): x[0] = x[0] + 1 print x[0] funkce3()