Skoop

Skoop tähistab programmis mingit kehtivuspiirkonda (või mõjupiirkonda), milles on muutujad seotud kindlate väärtustega. Võib-olla oled märganud, et funktsiooni sees kasutusele võetud muutujad on lokaalsed ja neid ei saa funktsioonist väljaspool kasutada. Miks on see nii?

Funktsioonid kui mustad kastid

Tihti on vaja teada ainult funktsiooni sisendeid ja väljundeid ning funktsiooni konkreetne implementatsioon pole oluline. Kui funktsioon kasutab ainult lokaalseid muutujaid, siis pole vaja muretseda, et mingid välised tegurid võiksid mõjutada funktsiooni käivitamisel saadud tulemust. Hea on vältida globaalsete muutujate kasutamist, sest nendega tekib oht, et muutuja kirjutatakse kuskil kogemata üle. Vea leidmiseks peaks suurema programmi puhul läbi vaatama sadu ridu. Allpool vaatame konkreetseid näited sellistest olukordadest.

Lokaalsed ja globaalsed muutujad

Vaid funktsiooni sees kasutuses olevaid muutujaid nimetatakse lokaalseteks muutujateks ja väljaspoole funktsioone kasutusele võetud muutujaid nimetetakse globaalseteks muutujateks. Esimesel juhul võime rääkida lokaalsest skoobist ja teisel juhul globaalsest skoobist.

Muutuja saab asuda kas globaalses skoobis või lokaalses skoobis, mõlemas olla ei saa.

Skoobist võib mõelda kui muutujate konteinerist. Lokaalne skoop tekib funktsiooni välja kutsumisel ja muutujad selles kaovad peale return-i. Eksisteerib vaid üks globaalne skoop, mis luuakse programmi käivitamisel.

Globaalsete muutujate kasutamine väikestes programmides on tihti mugav, kuid suuremate programmide puhul tasub neid mitte kasutada.

Näide.

# this is a global variable
a = 0

if a == 0:
    # this is still a global variable
    b = 1


def my_function(c):
    # this is a local variable
    d = 3
    print(c)
    print(d)


# now we call the function, passing the value 7 as the first and only parameter
my_function(7)

# a and b still exist
print(a)
print(b)

# c and d don't exist anymore -- these statements will give us name errors!
print(c)
print(d)

Visualiseerimine.

Lokaalses skoobis olevaid muutujaid ei saa kasutada globaalses skoobis.

def foo():
    bar = 20

foo()
print(bar)  # -> NameError: name 'bar' is not defined

Lokaalne skoop saab kasutada globaalseid muutujaid.

def f(x):
    return x + a

a = 5
print(f(3))  # -> 8

Kuna lokaalses skoobis pole muutujat a, siis seda otsitakse globaalsest skoobist. Visualiseerimine.

Lokaalne skoop ei saa kasutada muutujaid teises lokaalses skoobis.

def foo():
    dog = 5
    bar()
    print(dog)

def bar():
    dog = 333

foo()  # -> 5

Programm algab globaalsest skoobist, kus käivitatakse foo() ja selleks luuakse lokaalne skoop. Muutuja dog saab väärtuseks 5. Käivitatakse bar(), mis loob uue lokaalse skoobi, kus muutuja dog saab väärtuse 333, nüüd return-iga kaovad lokaalse skoobi muutujad. (Kui pole return kirjas, siis vaikimisi on return None). Nüüd funktsiooni foo() skoobis prinditakse dog, mis on selles skoobis endiselt väärtusega 5.

Visualiseerimine.

Sama nimega muutujad erinevates skoopides

Pythonis on võimalik nimetada muutujaid erinevates skoopides sama nimega. Lihtsuse mõttes on mõistlik seda siiski vältida.

Vaata, mis juhtub alljärgnevad koodis, kus on kolmes erinevas skoobis muutuja cheese.

def foo():
    cheese = 0
    print(f"From foo() scope: {cheese}")


def bar():
    cheese = 999
    print(f"From bar() scope: {cheese}")
    foo()
    print(f"From bar() scope: {cheese}")


cheese = 5
bar()
print(f"From global scope: {cheese}")

# output:
# From bar() scope: 999
# From foo() scope: 0
# From bar() scope: 999
# From global scope: 5

Visualiseerimine.

Globaalse muutuja muutmine

Globaalset muutujat on võimalik lokaalses skoobis muuta kasutades võtmesõna global. See ütleb pythonile, et selles skoobis viitab vastav muutuja globaalsele muutujale ja seega sellist lokaalset muutujat ei looda.

def foo():
    global cheese
    cheese = 3

cheese = 0
foo()
print(cheese)  # -> 3

Visualiseerimine.

Mittelokaalne skoop (nonlocal/enclosed scope)

Lokaalne skoop võib olla teise lokaalse skoobi sees seda nimetakse mittelokaalseks skoobiks. Kui on vaja sisemises lokaalses skoobis kasutada lähima välimise lokaalse skoobi muutujat, siis tuleb kasutada global asemel nonlocal.

def foo(b):

    def bar():
        nonlocal b
        b += 1

    b += 1
    print(b)  # -> 6
    bar()
    return b

a = 5
c = foo(a)
print(c)  # -> 7

Visualiseerimine.

Sisseehitatud skoop (built-in scope)

Sisseehitatud skoop on spetsiaalne Pythoni skoop, mis luuakse või laaditakse alati, kui käivitate skripti. See skoop sisaldab nimesid, nagu märksõnad, funktsioonid, erindid ja muud Pythoni sisseehitatud atribuudid. Nimed selles skoobis on saadaval kõikjal koodis. Python laeb selle automaatselt, kui käivitakse programm või skript. Näiteks print() on Pythoni sisseehitatud funktsioon ja seetõttu kuulub sisseehitatud skoopi.

LEGB reegel

LEGB reegel on omamoodi nimeotsingu protseduur, mis määrab Pythonis nimede otsimise järjekorra. Python otsib nimesid seestpoolt välja, alustades lokaalsest skoopist ja lõpetades sisseehitatud skoobiga.

Image not found

Rohkem lugemist

Skoopide visualiseerimine: http://pythontutor.com/
Python Scopes and Their Built-in Functions: https://www.knowledgehut.com/blog/data-science/python-scopes