11B: Zakres Zmiennej

Lekcja 11 składa się z trzech części A, B, C, które możesz wykonać w dowolnej kolejności.

W tej lekcji wyjaśnimy pojęcie zakresu zmiennej. Główną ideą to, że mogą istnieć dwie różne zmienne o tej samej nazwie, gdy mają różne zakresy. To znacznie ułatwia pisanie i edytowanie programów, zwłaszcza dużych. Będzie to również niezbędnym elementem w późniejszym temacie, rekursji

Przykład zakresu zmiennej

W tym przykładzie część naszego programu będzie następująca:

def square(x):
   value = x * x
   return value
Jest to funkcja, która oblicza kwadrat liczby x, na przykład square(5) zwraca 25. Załóżmy, że użyjemy nazwy square w innej części programu, która również wykorzystuje wartości zmiennej do innego celu:

# główne ciało programu zaczyna się tutaj
value = 17
fivesquared = square(5)
print(fivesquared, value)
Pytanie brzmi, co zostanie wydrukowane w tym scenariuszu? Jeśli nie wiemy jak działa Python, to widzimy dwie możliwości:

  1. Jedną z możliwości jest to, że Python uzna, że obie wartości zmiennych w jakiś sposób powinny być "zachowane oddzielnie". Tak więc wywołanie square zwróci 25, ale wartość w głównym ciele będzie nadal wynosić 17 i na wyjściu otrzymamy 25 17.
  2. Inna możliwość może być następująca, gdy wykonywany jest square, istniejąca wartość zmiennej zostanie nadpisana wartością 25 i na wyjściu otrzymamy 25 25.

Zobaczmy, co właściwie się stanie!

Widzimy, że zachowanie Pythona jest zgodne z wariantem #1. W rzeczywistości, za każdym razem, gdy funkcja jest wywoływana, nie można wpłynąć na żadną zmienną zdefiniowaną poza tą funkcją. Wszelkie instrukcje przypisujące wartości zmiennym mają wpływ tylko na "lokalną" zmienną, która jest "wewnątrz" wywoływanej funkcji. Powód, dla którego Python i większość innych języków działają w ten sposób, sprawiają, że dużo prostsze jest napisanie długich programów z wieloma funkcjami. W szczególności, kiedy definiujemy nową funkcję, zawsze możemy używać dowolnych nazw zmiennych wewnątrz funkcji (w tym takich, jak result, temp i i), nawet jeśli są one używane gdzie indziej w innych celach.

Aby zobaczyć to szczegółowo, spójrz na "Krok 6 z 8" w wizualizatorze. Zauważ, że istnieją dwie różne zmienne wartości: jedna wewnątrz funkcji square i jedna na zewnątrz (w obszarze "globalnym").

Zadanie wielokrotnego wyboru: Wewnątrz i na Zewnątrz
Co otrzymamy na wyjściu następującego programu?

x = "outer"
def xReplace(value):
x = value
xReplace("inner")
print(x)
Poprawnie! Instrukcja x = value wpływa tylko na lokalną wersję zmiennej x wewnątrz funkcji. Globalna wersja x nie zmienia się. (Więc funkcja xReplace jest bezużyteczna i nigdy nie daje żadnego efektu.)

Inną, podobną koncepcją do zakresu jest przestrzeń nazw; Przestrzeń nazw jest jak zakres pakietu. Tak więc, jeśli nawet zaimportujesz pakiet (np. math), w którym użyto nazwy zmiennej x, nie pokrywają się one ze zmienną x używaną przez program, ponieważ leżą w różnych przestrzeniach nazw.

Patrząc na Zewnątrz

Są sytuacje, w których chcemy zmieszać zmienne z zakresu lokalnego i globalnego. Na przykład, mamy pewną zmienną zainicjowaną na początku programu, ale chcemy, aby nasze wywoływane funkcje były w stanie odczytać tą zmienną.

Przykład
Odczytywanie globalnej zmiennej z wnętrza funkcji

Tutaj, zakres lokalny nie zawierał zmiennej o nazwie favouriteTopping, ale nie spowodowało to błędu. Reguła Pythona do sprawdzania zmiennych polega na tym, że jeśli sprawdzana zmienna nie istnieje w zasięgu lokalnym, to szukana jest w zasięgu globalnym. W naszym przypadku, rzeczywiście, favouriteTopping została znaleziona w zasięgu globalnym. (W bardziej ogólnym przypadku, gdy jedna funkcja ciała wywołuje inną funkcję, mamy trzy zakresy: Python zawsze najpierw sprawdza zakres "najbardziej lokalny" i przechodzi krok po kroku do zakresu globalnego, dopóki nie zostanie znaleziona zmienna).

Dwa z powyższych przykładów, z orderPizzas i xReplace są pod względem składniowym niemal identyczne. Dlaczego Python tworzy nową lokalną zmienną x w xReplace, ale nie ma nowego favouriteTopping w orderPizzas? Reguła Pythona jest następująca: jeśli tylko czytasz zmienną, to nie tworzona jest żadna nowa lokalna zmienna; ale jeśli zapisujesz do zmiennej, choćby tylko raz, to zmienna jest traktowana jako lokalna w ciele funkcji. (Jest to najczęstsza przyczyna UnboundLocalError: zobacz te dwa pytania [1, 2] w oficjalnej dokumentacji Pythona.)

Argumenty funkcji są zawsze traktowane jako nowe lokalne zmienne, jak pokazano poniżej we fragmencie kodu (próbuje zresetować zmienną g do 0, ale nie powiedzie się).

 Zmiany global

Podobnie jak wiele innych rzeczy, normalna procedura działa, jak opisano powyżej, dla 99% wszystkich sytuacji. Ale dla 1% nie, a ty może naprawdę chcesz zmienić zmienną globalną z poziomu funkcji. Python zawsze pozwala to zrobić z użyciem instrukcji global.

Oto modyfikacja wcześniejszego przykładu xReplace; deklarowanie w funkcji zmiennej jako global umożliwia zmianę wartości globalnej z poziomu tej funkcji.

Jak wspomniano wcześniej, odczytywanie globalnej zmiennej nie wymaga użycia instrukcji global; tylko zapisywanie. To wniosek z tej lekcji!