Python - Namespace i Scope


Šta je Namespace u Python-u?

Ako ste ikada pročitali 'The Zen of Python' (ovo unesite u interpretator Python-a), u zadnjem redu stoji da su prostori imena sjajna ideja. Pa koji su to tajanstveni prostori imena? Pogledajmo prvo kako se zove. Ime (Name) (koje se naziva i identifikator) je jednostavno ime dato objektima. Sve što je u Python-u je objekt. Ime je način pristupa osnovnom objektu. Na primjer, kada radimo zadatak a = 2, 2 je objekt pohranjen u memoriji, a a je ime s kojim ga povezujemo. Možete dobiti adresu (u RAM-u) nekog objekta putem ugrađene funkcije id(). Pogledajmo kako da ga koristite.

# Napomena: Možete dobiti različite vrijednosti za id

a = 2
print('id(2) =', id(2))

print('id(a) =', id(a))

Ovdje se oba odnose na isti objekt 2, pa imaju isti id(). Učinimo stvari malo zanimljivijima.

# Napomena: Možete dobiti različite vrijednosti za id

a = 2
print('id(a) =', id(a))

a = a+1
print('id(a) =', id(a))

print('id(3) =', id(3))

b = 2
print('id(b) =', id(b))
print('id(2) =', id(2))

Šta se događa u gore navedenom slijedu koraka? Upotrijebimo dijagram da to objasnimo:





U početku se kreira objekt 2 i s njim se povezuje ime a, kada napravimo a = a + 1, kreira se novi objekt 3 i sada je a pridružen ovom objektu. Imajte na umu da id(a) i id(3) imaju iste vrijednosti. Nadalje, kad se izvrši b = 2, novo ime b povezuje se s prethodnim objektom 2. Ovo je efikasno, jer Python ne mora stvoriti novi duplikat objekta. Ova dinamična priroda vezivanja imena čini Python moćnim. Ime bi se moglo odnositi na bilo koju vrstu objekta.

>>> a = 5
>>> a = 'Hello World!'
>>> a = [1,2,3]

Sve je to valjano i odnosi se na tri različite vrste objekata u različitim instancama. Funkcije su i objekti, tako da se naziv može odnositi i na njih.

def printHello():
    print("Hello")

a = printHello

a()

Isto ime a može se odnositi na funkciju i možemo je nazvati funkcijom pomoću ovog imena.



Šta je prostor imena (Namespace) u Pythonu?

Sada kada razumijemo koja su imena, možemo preći na koncept prostora imena. Jednostavno rečeno, prostor imena je zbirka imena. U Pythonu možete zamisliti prostor imena kao mapiranje svakog imena koje ste definisali u odgovarajuće objekte. U određenom vremenu mogu postojati različiti prostori s imenima, ali su potpuno izolovani.

Prostor imena koji sadrži sva ugrađena imena kreira se kada pokrenemo Python interpreter i postoji sve dok interpretator radi. To je razlog što su nam ugrađene funkcije poput id(), print() itd. uvijek dostupne iz bilo kog dijela programa. Svaki modul kreira svoj vlastiti globalni prostor imena. Ovi različiti imenski prostori su izolovani. Moduli mogu imati različite funkcije i klase. Lokalni prostor imena stvara se kada se zove funkcija koja je u njoj definisala sva imena. Sličan je slučaj i sa klasom. Sljedeći dijagram može pomoći da se pojasni ovaj koncept.






Opseg (Scope) promenljive u Python-u

Iako su definisani različiti jedinstveni prostori imena, možda im nećemo moći pristupiti iz svih dijelova programa. Koncept opsega (scope) dolazi u obzir. Opseg (scope) je dio programa odakle se imenskom prostoru može pristupiti direktno bez ikakvog prefiksa. U bilo kom trenutku postoje najmanje tri ugniježdena područja.

  • Opseg (Scope) trenutne funkcije koja ima lokalna imena
  • Opseg (Scope) modula koji ima globalna imena
  • Krajnji opseg (scope) koji ima ugrađena imena

Kada se referenca napravi unutar funkcije, ime se traži u lokalnom prostoru imena, zatim u globalnom prostoru imena i konačno u ugrađenom prostoru imena. Ako unutar druge funkcije postoji funkcija, novi opseg je ugniježden unutar lokalnog opsega.


Primjer opsega (scope) i prostora imena u Python-u

def outer_function():
    b = 20
    def inner_func():
        c = 30

a = 10

Ovdje je varijabla a u globalnom prostoru imena. Varijabla b je u lokalnom imenskom prostoru external_function(), a c je u ugniježdenom lokalnom imenskom prostoru inner_function(). Kada smo u inner_function(), c nam je lokalno, b je nelokalno, a a globalno. Možemo čitati kao i dodijeliti nove vrijednosti za c, ali možemo čitati samo b i a iz inner_function().

Ako pokušamo dodijeliti vrijednost kao b, stvara se nova varijabla b u lokalnom prostoru imena koja je različita od nelokalne varijable b. Ista stvar se događa kada a dodijelimo vrijednost. Međutim, ako a proglasimo globalnim, sve reference i dodjele idu globalnom a. Slično tome, ako želimo ponovno povezati varijablu b, ona se mora proglasiti kao nelokalna. Sljedeći primjer će ovo dodatno pojasniti.

def outer_function():
    a = 20

    def inner_function():
        a = 30
        print('a =', a)

    inner_function()
    print('a =', a)


a = 10
outer_function()
print('a =', a)

U ovom su programu tri različite varijable, a definisane su u zasebnim prostorima imena i njima se pristupa u skladu s tim. Pogledajmo sljedeći primjer:

def outer_function():
    global a
    a = 20

    def inner_function():
        global a
        a = 30
        print('a =', a)

    inner_function()
    print('a =', a)


a = 10
outer_function()
print('a =', a)

Ovdje su sve reference i dodjele globalnom a zbog upotrebe ključne riječi global.