Zmienne i parametry są lokalne

Wyrażenie przypisania w środku funkcji tworzy zmienną lokalną o nazwie zmiennej, stojącej po lewej stronie operatora przypisania. Nazywamy ją lokalną, ponieważ istnieje tylko w środku funkcji i nie można używać jej poza nią. Na przykład zerknijmy na funkcję square:

(bad_local)

Po naciśnięciu przycisku ‘last >>’ zobaczycie komunikat błędu. Gdy chcemy odwołać się do y w lini nr 6 (poza funkcją) Python szuka globalnej zmiennej o nazwie y, ale jej nie znajduje. Kończy się to błędem: Name Error: 'y' is not defined. (Błąd nazwy: ‘y’ nie jest zdefiniowane).

Zmienna y istnieje tylko w momencie, gdy funkcja jest wołana — nazywamy to czasem życia. Gdy praca danej funkcji się kończy, zmienne lokalne są likwidowane. Codelens pomaga nam to sobie wyobrazić, ponieważ zmienne lokalne znikają w momencie, gdy funkcja zwraca wartość. Wróć na początek i przejdź krok po kroku przez program, zwracając szczególną uwagę na zmienne, które są tworzone, kiedy funkcja jest wołana. Zauważ też, kiedy są kolejno niszczone w momencie, gdy funkcja kończy działania.

Parametry formalne również są zmiennymi lokalnymi. Przykładowo czas życia zmiennej x zaczyna się, gdy funkcja square jest wołana, a kończy się, gdy funkcja kończy działanie.

Nie jest więc możliwe, by funkcja przypisała lokalnej zmiennej jakąś wartość, zakończyła działanie, a przy kolejnym wywołaniu odzyskała ową zmienną. Każdorazowe wywołanie funkcji tworzy zmienne lokalne, których czas życia ograniczony jest czasem wykonywania funkcji i kończy się w momencie, gdy funkcja zwraca wartość.

Z drugiej jednak strony, funkcje mogą odwoływać się do zmiennych globalnych. Uważa się to jednak za złą praktykę przez niemal wszystkich programistów i powinno się tego unikać. Spójrzmy na poniższy niedorzeczny wariant funkcji square.




(badsquare_1)

Pomimo tego, że funkcja badsquare będzie działać, jest ona źle napisana. Pokazujemy ją tu, aby pokazać jak zmienne są w języku Python wyszukiwane. Na pierwszym miejscu Python szuka nazw zmiennych zdefiniowanych jako zmienne lokalne dla danej funkcji. Nazywamy to zasięgiem lokalnym (local scope). Jeżeli zmiennej o danej nazwie nie ma w zasięgu lokalnym, wtedy interpreter zaczyna szukać wśród zmiennych globalnych, czy też jak mówimy przeszukuje zasięg globalny. Dokładnie taki przypadek zilustrowany jest tym przykładem. Zmienna power nie jest znaleziona lokalnie w funkcji badsquare, ale istnieje jako zmienna globalna. Prawidłową konstrukcją byłoby podanie zmiennej power jako parametru do funkcji. Jako ćwiczenie proponujemy, abyś przepisał funkcję badsquare tak, aby miała drugi parametr o nazwie power.

Poniżej znajdziecie kolejny przykład na rozróżnianie zmiennych lokalnych i globalnych. Przypisania realizowane lokalnie w funkcjach nie zmienią wartości zmiennych zdefiniowanych na zewnątrz funkcji. Prześledźmy ten przypadek w codelens:

(cl_powerof_bad)

Uruchom ten kod w codelens. Co możesz powiedzieć o wartościach, jakie przyjmuje zmienna power w zasięgu lokalnym w porównaniu do wartości w zasięgu globalnym?

Wartość zmiennej power w zasięgu lokalnym jest inna od tej w zasięgu globalnym. Dzieje się tak, ponieważ w tym przykładzie zmienna power znalazła się po lewej stronie przypisania power = p. Kiedy nazwa zmiennej użyta jest po lewej stronie przypisania Python tworzy zmienną lokalną. Jeżeli przez przypadek nazwa zmiennej lokalnej jest taka sama jak nazwa zmiennej globalnej, to mówimy, że zmienna lokalna przesłania zmienną globalną. Przesłanianie oznacza, że dostęp do zmiennej globalnej jest niemożliwy, ponieważ zmienna lokalna będzie znaleziona jako pierwsza przez interpreter. Jest to kolejny (dobry) powód na nieużywanie zmiennych globalnych. Jak widać powoduje to, że kod staje się nieczytelny i trudny do zrozumienia.

Aby zrozumieć powyższe idee jeszcze lepiej spójrzmy na ostatni przykład. W środku funkcji square damy przypisanie do parametru x. Nie ma zbytniego sensu tak robić, poza tym, że chcemy podkreślić fakt, że parametr x jest też zmienną lokalną. Śledząc zachowanie zmiennej x w codelens zobaczycie, że pomimo, że zmienna lokalna x we funkcji square przyjmuje wartość 0, to globalna zmienna x przez cały czas trzyma 2. Dla początkujących programistów może być lekko mylące to, że przypisanie nowej wartości do parametru formalnego spowoduje zmianę wartości zmiennej, która została przekazana do owego parametru formalnego, a na dodatek nosi tę samą nazwę. Poniższy przykład jasno pokazuje, że język Python tak nie działa.

(cl_change_parm)

Sprawdź swoją wiedzę

func-3-1: Co to jest zasięg zmiennej?




func-3-2: Co to jest zmienna lokalna?




func-3-3: Czy można użyć tej samej nazwy dla zmiennej lokalnej i globalnej.




Następna część - Wzorzec inkrementalny