Funkce s lokální a globální proměnnou – Python – Fórum – Programujte.com
 x   TIP: Přetáhni ikonu na hlavní panel pro připnutí webu

Funkce s lokální a globální proměnnou – Python – Fórum – Programujte.comFunkce s lokální a globální proměnnou – Python – Fórum – Programujte.com

 

Toto vlákno bylo označeno za vyřešené — příspěvek s řešením.
kocourOggy0
Newbie
23. 7. 2012   #1
-
0
-

Mam menší problém s globálními a lokálními proměnnými. Zkusil jsem si vytvořit 3 funkce, viz kód níže. První funkce pouze čte globální proměnnou, druhá funkce vytváří vlastní lokální proměnnou se stejným názvem jako globální proměnná a tiskne ji. Třetí funkce dělá stejné úkony jako první a druhá funkce dohromady, ale bohužel nefunguje, dokonce odmítá vytisknout globální proměnnou, která je hned na prvním řádku. Mohl by mi prosím někdo vysvětlit, proč třetí funkce odmítá poslouchat?

kód:

def fce_1():
    # Precte hodnotu globalni promenne 'spam'.
    print "tisknu hodnotu globalni promenne 'spam':", spam

def fce_2():
    # Vytvori lokalni promennou 'spam' a precte ji.
    spam = 1
    print "toto je moje vlastni lokalni promenna 'spam':", spam

def fce_3_nefunkcni():
    # Precte hodnotu globalni promenne 'spam'.
    # Vytvori lokalni promennou "spam" a precte ji.
    print spam
    spam = 1
    print spam

spam = 10
fce_1()
fce_2()
fce_3_nefunkcni()


výpis:

>>> 
tisknu hodnotu globalni promenne 'spam': 10
toto je moje vlastni lokalni promenna 'spam': 1

Traceback (most recent call last):
  File "C:/PYprogramy/zkouska_fce.py", line 20, in <module>
    fce_3_nefunkcni()
  File "C:/PYprogramy/zkouska_fce.py", line 13, in fce_3_nefunkcni
    print spam
UnboundLocalError: local variable 'spam' referenced before assignment
Nahlásit jako SPAM
IP: 89.24.50.–
Věčný začátečník nejen v Pythonu.
Řešení
zlz
~ Anonymní uživatel
634 příspěvků
23. 7. 2012   #2
-
+1
-
Zajímavé
Vyřešeno Nejlepší odpověď

Zdroják se nejdříve zpracuje (tam si překladač všimne zápisu) a až pak provádí (a proměnná už je lokální).

Nahlásit jako SPAM
IP: 78.156.159.–
Brilantní modř
~ Anonymní uživatel
1 příspěvek
23. 7. 2012   #3
-
-1
-
Mimo téma

He he, v Perlu mi tohle funguje bez problémů:

#!/usr/bin/perl
use strict;
use warnings;
my $spam = 10;
sub fce_1 {
    print($spam, "\n");
}
sub fce_2 {
    my $spam = 1;
    print($spam, "\n");
}
sub fce_3 {
    print($spam, "\n");
    my $spam = 1;
    print($spam, "\n");
}
# my $spam = 10; ## Musí být deklarováno před suby.
fce_1(); ## 10
fce_2(); ## 1
fce_3(); ## 10, 1
print($spam, "\n"); ## 10

Nahlásit jako SPAM
IP: 83.208.15.–
Wrunx0
Duch
23. 7. 2012   #4
-
+1
-
Zajímavé

A proč by to nešlo v Pythonu (v. 2.7.1) ?

def f():
  global spam # připomeneme že spam je globální
  print spam
  spam=3 # a vytvoříme lokální
  print spam

# a spustíme ten cirkus
>>>spam=1
>>>f()

1
3

ale osobně bych do toho nešel, takovéhle fintičky vedou obvykle k obtížně hledatelným zádrhelům :-)

protože nové volání f() už ukáže něco jiného ;-)

A pro účely ladění, co se s deklarací proměnné (v tomto případě "spam") děje v průběhu procesu, se dá pohodlně trasovat např. příkazy globals()["spam"] a locals()["spam"] (obecně: globals() vypíše globální, locals() lokální proměnné a jejich obsahy)

Nahlásit jako SPAM
IP: 188.120.195.–
kocourOggy0
Newbie
23. 7. 2012   #5
-
0
-

#4 Wrunx
Vím, že by tento problém šel vyřešit různě

def fce_1():
    # Precte hodnotu globalni promenne 'spam'.
    print "tisknu hodnotu globalni promenne 'spam':", spam

def fce_2():
    # Vytvori lokalni promennou 'spam' a precte ji.
    spam = 1
    print "toto je moje vlastni lokalni promenna 'spam':", spam

def fce_3_funkcni(x):
    # Precte hodnotu ze zadaneho parametru
    # Precte lokalni promennou spam, kterou funkce vytvorila
    print x, "tisknu se pomoci parametru"
    spam = 1
    print spam, "tohle je moje vlastni lokalni promenna"
    

spam = 10
fce_1()
fce_2()
fce_3_funkcni(spam)

nebo jednoduše přejmenovat proměnnou v té fce_3 na spam_1 apod.

Chtěl jsem jenom vědět, jak daleko mě Python pustí s lokálními a globálními proměnnými . U fce_3_nefunkcni už mi to však Python nezkousl, i když mi ta varianta přišla zcela přijatelná.

Nahlásit jako SPAM
IP: 89.24.92.–
Věčný začátečník nejen v Pythonu.
kocourOggy0
Newbie
23. 7. 2012   #6
-
0
-

#2 zlz

Promiň, že to budu nejspíš opakovat, ale chtěl bych se raději ujistit.

Překladač tedy projede celým kódem a u fce_3 si všimne, že se vytváří lokální proměnná spam. Python následně bude považovat jakoukoliv proměnnou s názvem spam ve fce_3 za lokální, ta se však vytváří až na další řádce. Python vyhodí chybovou hlášku, protože žádná lokální proměnná spam, kterou voláme, nebyla dosud ve fce_3 vytvořena.

def fce_3_nefunkcni():
    print spam
    spam = 1
    print spam
Nahlásit jako SPAM
IP: 89.24.91.–
Věčný začátečník nejen v Pythonu.
yetty
~ Redaktor
+5
Super člen
23. 7. 2012   #7
-
+1
-
Zajímavé

#6 kocourOggy
Tak to zhruba je. No vlastně jen skoro. Implicitně je z globální proměnné povolené pouze čtení, ne zápis. Protože přepisovat si globální proměnné nadělá spoustu zmatku a je to opravdu něco, čemu by se řádný programátor měl vyhnout.

Nicméně pro úplnost, možné je i to. Je potřeba použít klíčové slovíčko global.

def fce_3():
    global spam
    print spam
    spam = 1
    print spam

To samozřejmě pozmění globální proměnnou: 

>>> spam = 2
>>> print spam
2
>>> fce_3()
2
1
>>> print spam
1

Koukám, že už to přede mnou napsal Wrunx, sorry, přehlédl jsem.

Nahlásit jako SPAM
IP: 46.23.51.–
zlz
~ Anonymní uživatel
634 příspěvků
24. 7. 2012   #8
-
+1
-
Zajímavé

#6 kocourOggy
Přesně tak. (Technicky vzato ta proměnná je vytvořená, resp. existuje v lokální tabulce symbolů té funkce, ale nemá přiřazenou hodnotu. Proto je to UnboundLocalError a ne NameError).

Nahlásit jako SPAM
IP: 80.188.216.–
Stilgar
~ Anonymní uživatel
4 příspěvky
3. 4. 2017   #9
-
0
-

Wrunx: protože nové volání f() už ukáže něco jiného ;-)

Proc ukaze neco jineho?

Resim ted podobny problem u rekurze, kdy si chci menit globalni promenou (potrebuju si ukladat vysledek). Ale dela to neplechu.

Jedine co me dalsiho napada jak se vyhnout globalnim promenym je si vysledek ukladat do souboru a az ho budu potrebovat pro dalsi pouziti tak si ho nactu z tohoto souboru.

Nahlásit jako SPAM
IP: 85.160.56.–
Zjistit počet nových příspěvků

Přidej příspěvek

Toto téma je starší jak čtvrt roku – přidej svůj příspěvek jen tehdy, máš-li k tématu opravdu co říct!

Ano, opravdu chci reagovat → zobrazí formulář pro přidání příspěvku

×Vložení zdrojáku

×Vložení obrázku

Vložit URL obrázku Vybrat obrázek na disku
Vlož URL adresu obrázku:
Klikni a vyber obrázek z počítače:

×Vložení videa

Aktuálně jsou podporována videa ze serverů YouTube, Vimeo a Dailymotion.
×
 
Podporujeme Gravatara.
Zadej URL adresu Avatara (40 x 40 px) nebo emailovou adresu pro použití Gravatara.
Email nikam neukládáme, po získání Gravatara je zahozen.
-
Pravidla pro psaní příspěvků, používej diakritiku. ENTER pro nový odstavec, SHIFT + ENTER pro nový řádek.
Sledovat nové příspěvky (pouze pro přihlášené)
Sleduj vlákno a v případě přidání nového příspěvku o tom budeš vědět mezi prvními.
Reaguješ na příspěvek:

Uživatelé prohlížející si toto vlákno

Uživatelé on-line: 0 registrovaných, 14 hostů

Podobná vlákna

Operátor << u globalni funkce — založil ingiraxo

Lokalni promenna — založil BigBear

Lokalni extremy — založil Grav

 

Hostujeme u Českého hostingu       ISSN 1801-1586       ⇡ Nahoru Webtea.cz logo © 20032024 Programujte.com
Zasadilo a pěstuje Webtea.cz, šéfredaktor Lukáš Churý