Zapiski
O imenskih prostorih (namespace) smo se pogovarjali že pri Programiranju 1. V resnici smo se jih bolj kot ne le dotaknili. Kdor je te stvari že pozabil, naj pogleda zapiske na to temo pri Programiranju 1. Takrat smo risali škatlice, ki so predstavljali objekte, in do vsakega objekta, je vodila ena ali več puščic. Na drugi strani puščic so bila imena: vsako ime se je torej nanašalo na nek objekt. Do objektov, na katere se ni neposredno nanašalo nobeno ime, smo lahko prišli posredno: do objektov, shranjenih v seznamu, lahko pridemo z imenom seznama in indeksom; do atributov objektov pridemo z imenom objekta, piko in imenom atributa...
Povedali smo, da ima vsaka funkcija svoj "nabor" imen, prav tako imajo svoje nabore imen moduli in, na nek drug način, tudi razredi in slovarji. Tu bomo začeli danes.
Še prej pa moramo eno stvar povedati bolj formalno.
Vezava imen
Kot stalno ponavljamo: imamo imena in objekte. Imena so vezana (bound) na objekte.
Odkod se vzamejo imena? Ali, če hočete, "spremenljivke"? Odkod se lahko pojavijo? Formalneje, kako lahko privežemo (bind) ime na objekt.
- S prirejanjem:
x = 42
naredi objekt 42 in veže imex
nanj. Kadar v prirejanju razpakiramo terko, npr.a, b = 3, 6
, vežemo dve imeni. - Z argumenti funkcij: če funkcijo definiramo z
def f(a, b)
, bosta v funkciji imenia
inb
, ki bosta vezani na argumente, ki smo jih dali funkciji. - Z zanko for:
for i in range(5)
vežei
na vrednosti, ki jih generirarange
. V vsaki ponovitvi zanke jei
vezan na drugo mesto. - Uvažanje modulov:
import math
veže imemath
na modul,import math as matematika
veže imematematika
na modul, ki mu sicer pravimomath
, infrom math import sin, cos
veže imenisin
incos
na funkcijisin
incos
iz modulamath
. - Definicije funkcij in razredov vežejo njihova imena na te funckije in
razrede -
def f(x): return 42
veže imef
na to funkcijo,class A: pass
pa imeA
na ta (ničvredni) razred. - Operator
as
v kontekstih (with
) in prestrezanjih izjem (except
). O slednjem nekaj malega vemo, o drugem pa se bomo tule definitivno pogovarjali, vendar ne danes.
To je vse: imena se vežejo na teh šest načinov in nobenega drugega.
Tema, o kateri se bomo pogovarjali danes, pa so imenski prostori, namespace, "zbirke imen". Teh zbirk je več.
Da kar takoj začnem s spoilerjem: v bistvu so imena shranjena v slovarjih. Včasih zares, včasih pa se vsaj delajo, da so. Ključi tega slovarja so imena, vrednosti pa objekti, na katere se ta imena nanašajo.
Globalni imenski prostor
To je najlažje videti v globalnem imenskem prostoru. Globalne spremenljivke
(torej tiste, ki niso bile vezane znotraj funkcije ali razreda), so shranjene
v slovarju, ki ga Python pokaže prek funkcije globals()
.
>>> globals()
{'__name__': '__main__'}
>>> x = 12
>>> globals()
{'__name__': '__main__', 'x': 12}
>>> ime = "Benjamin"
>>> globals()
{'ime': 'Benjamin', 'x': 12, '__name__': '__main__'}
globals()
nam torej vrne slovar z imeni in pripadajočimi vrednostmi. Ta že v
začetku ni prazen. V njem se nahaja, recimo, čudno ime __name__
z vrednostjo
"__main__"
; kaj je to in čemu služi, bomo še videli, ni pa posebej pomembno.
Še manj zanimive so nekatere druge stvari, ki sem jih zaradi preglednosti kar
pobrisal.
Ko napišemo x = 12
, se v slovarju pojavi nov element; ključ je niz "x"
,
vrednost pa 12. Podobno se zgodi, ko napišemo ime = "Benjamin"
.
Zdaj pa vtipkajmo x + 7
. Python najprej preveri, ali obstaja ime x
:
pogleda v tale slovar. Če obstaja ključ x
, v izrazu x + 7
uporabi
pripadajočo vrednost (globals()["x"]
). Če ga ni, javi napako.
Napišem lahko tudi del x
, kar pobriše ime x
- torej, pobriše
dotični ključ (in, seveda, pripadajočo vrednost) iz slovarja.
>>> del x
>>> globals()
{'ime': 'Benjamin', '__name__': '__main__'}
Da je to v resnici slovar, ki veže imena na vrednosti, se prepričamo tako, da ga uporabljamo za "ročno" vezanje imen.
>>> imena = globals()
>>> imena
{'ime': 'Benjamin', 'imena': {...}, '__name__': '__main__'}
Zdaj se ime imena
nanaša na slovar, ki ga vrne globals()
. Ta slovar
je slovar imen in zato, he he, vsebuje tudi ključ "imena"
, pripadajoča
vrednost pa je kar ta slovar sam (in vsebuje ključ "imena"
in tako naprej).
No, nisem hotel pokazati tega. :) Zanimivo je tole: v slovar imena
dodajmo kak nov element:
>>> imena["a"] = 42
>>> imena["s"] = [1, 2, 3]
>>> imena
{'a': 42, 'ime': 'Benjamin', 's': [1, 2, 3], 'imena': {...},
'__name__': '__main__'}
S tem sta a
in s
v resnici dve novi spremenljivki:
>>> a
42
>>> s
[1, 2, 3]
Če torej napišemo a = 42
(kot bi počeli normalno) je to samo bližnjica za
globals()["a"] = 42
(če smo natančni, bližnjica za
globals().__setitem__("a", 42)
, ampak tako daleč v drobovje Pythona danes še
ne bomo rinili).
Podobno je x + 7
samo bližnjica za globals()["x"] + 7
. V resnici se prvo
"prevede" v drugo (ali, če smo natančni, v nekaj podobnega drugemu).
Kar smo pravkar videli, ni posebej uporabno. Tu je, ker pač Python tega ne skriva. Ni pa mišljeno, da bi se to uporabljalo. Tudi mi smo pogledali samo zato, da smo videli, kako Python v resnici deluje. To nam bo namreč pomagalo razumeti, kar sledi.
Lokalne shrambe
Vemo, da ima vsaka funkcija svoje spremenljivke, svoja imena. Kako to deluje,
najbrž slutimo: vsaka ima svoj slovar. Do njega ne pridemo prek globals()
,
temveč prek locals()
. Kar takoj poškilimo vanj.
>>> def f(x, y):
... z = 13
... print(locals())
...
>>> f(1, "Benjamin")
{'y': 'Benjamin', 'x': 1, 'z': 13}
Lokalne spremenljivke, ki jih pozna f
, so torej x
in y
, ki ju je dobila
kot argument, in z
, ki jo je ustvarila kasneje.
Funkcije imajo dostop tudi do globalnih spremenljivk. Tudi te lahko vidimo.
>>> def f(x, y):
... z = 13
... print(locals())
... print(globals())
...
>>> f(1, "Benjamin")
{'y': 'Benjamin', 'x': 1, 'z': 13}
{'a': 42, 'b': 43, 'ime': 'Benjamin', 'f': <function f at 0x10a3950c8>,
's': [1, 2, 3], 'spremenljivke': {...}, '__name__': '__main__'}
Vse torej deluje podobno kot prej, le da vsaka funkcija uporablja svoj lokalni slovar.
(Vsaj v teoriji. V praksi Python od verzije 2.nekaj naprej goljufa in lokalnih
spremenljivk ne shranjuje v slovarje, temveč z njimi dela na nek drug, hitrejši
način. Še vedno ima funkcijo locals()
, ki se dela, da tak slovar obstaja -
vendar to naredi tako, da ga na hitro sestavi, kadar ga želimo videti. Da tega
slovarja v resnici ni, bi se prepričali tako, da bi vanj kaj dodali. Za razliko
od primera s slovarjem globals()
, ki je resničen, tisto, kar dodamo v
locals()
ne pojavi kot lokalna spremenljivka.)
Mimogrede opazimo, da je ena od globalnih spremenljivk tudi funkcija f
. To
je razumljivo: funkcija je objekt in ima ime, pod katerim jo lahko prikličemo
in pokličemo. Ime f
smo na funkcijo vezali z def f(x, y)
.
Več funkcij
Kaj pa se dogaja, če imamo več funkcij, ki se kličejo med seboj? To si oglejmo na klasičnem primeru iskanja popolnih števil, ki ga običajno pokažem pri Programiranju 1.
def delitelji(n):
d = []
for i in range(1, n):
if n % i == 0:
d.append(i)
return d
def vsota(s):
v = 0
for e in s:
v += e
return v
def popolno(n):
return vsota(delitelji(n)) == n
def popolna_do(n):
p = []
for i in range(2, n + 1):
if popolno(i):
p.append(i)
return p
print(popolna_do(1000))
V program postavimo prekinitveno točko in mu počasi sledimo do nekje znotraj
funkcije delitelji
. Potem pa poglejmo, kaj PyCharm kaže levo spodaj.
Ignorirajte execfile
in vse, kar je pod njim; to je PyCharmova šara. Naš
program se začne pri module
, kakor PyCharm iz nekega razloga imenuje naš
program. Ta je v 27. vrstici skočil v funkijo popolna_do
. Ta je v 23. vrstici
skočila v funkcijo popolno
, ki je v 17. vrstici skočila v funkcijo
delitelji
. Python si vse te stvari zapomni - saj si jih mora, da se bo znal
vračati čez vse te klice.
Če pogledamo z druge strani: katera vrstica programa se trenutno izvaja? Četrta
vrstica, znotraj funkcije delitelji
. No, klic funkcije delitelji
je prekinil
izvajanje v 17. vrstici, ko je šlo za funkcijo popolno
. Ko bo funkcija
delitelji
končana, se bo izvajanje programa nadaljevalo v 17. vrstici. In ko
bo končana funkcija popolno
, se bo izvajanje nadaljevalo v 23. vrstici, kjer
je bilo prekinjeno zaradi klica te funkcije. (V resnici si Python ne zapomni
vrstice, kjer se je izvajanje "prekinilo", ker je skočil v neko funkcijo;
zapomniti si mora kar mesto znotraj vrstice - oziroma nekaj podobnega.)
Tako kot Python zlaga spremenljivke (no, imena in vrednosti) v slovar, zlaga te
podatke o izvajanju v nekakšen seznam. Samo "nekakšen seznam" iz dveh razlogov.
Kot prvo, ne gre za Pythonov seznam - za razliko od globals
, ki je v resnici
čisto običajen Pythonov slovar. Drugo, beseda "seznam" ima v terminologiji
podatkovnih struktur določen pomen in tule ne bi bila prav ustrezna. V resnici
se tej stvari, v katero Python sklada podatke o tem, od kod je skočil kam (da
bi vedel, kam se mora vrniti), reče sklad. PyCharm nam torej kaže
sklad klicev.
Na skladu niso samo podatki o tem, kam se je potrebno vrniti. Python poleg tega na skladu shranjuje tudi slovarje lokalnih spremenljivk. (Spet z opombo, da novejše verzije Pythona nekoliko goljufajo; končni učinek je vseeno isti, kot da bi to počel.) Če v PyCharmu klikamo po skladu, nam le-ta kaže lokalne spremenljivke funkcije, na katero smo kliknili - točneje, lokalne spremenljivke, ki so znane v trenutku, ko se je izvajanje te funkcije "prekinilo" zaradi klica.
Če je koga pri rekurziji motilo, da funkcija povozi svoje lastne spremenljivke: ne, ne povozi jih. Ob vsakem klicu se na sklad postavi nov slovar.
Pravila za iskanje imen
Pythonovi programi so razdeljeni v "bloke". Bloki so funkcije, razredi in "moduli" (zakaj je modul pod narekovaji, bomo videli). Python vsako ime najprej išče v lokalnem bloku (torej znotraj funkcije ali razreda - kako lahko išče nekaj znotraj razreda, bomo še videli). Če imena ni tam, pogleda v globalni blok. Če ga ni niti tam, javi napako.
n = 12
def f():
print(n)
Kaj se izpiše, če pokličemo f
? 12, seveda. Ker n
-ja ni med lokalnimi imeni,
ga najde med globalnimi.
def f():
print(m)
Če pokličemo to funkcijo, se (ob predpostavki, da niti v globalnem prostoru
ni nobenega m
-ja) sproži napaka
NameError: name 'm' is not defined
Kaj pa tole?
n = 12
def f():
print(n)
n = 5
n = 5
, ki sledi print
-u, ne bi smel ničesar spremeniti. Da, lahko bi bilo
narejeno tako. Vendar ni. Python goljufa in spremenljivke v resnici niso
zbrane v slovarju locals
. Da bi programi tekli hitreje, Python odkrije
imena že med prevajanjem funkcije (če kdo misli, da se programi v Pythonu za
razliko od Javanskih in Cjevskih ne prevajajo, se moti) ter pripravi prostor
zanje na nek učinkovitejši način. Posledično so vsa imena, ki jih prirejamo
vrednost znotraj funkcije, lokalna imena. Python ve, da so lokalna in jih
išče v lokalnem prostoru. Če torej pokličemo gornjo funkcijo, dobimo:
UnboundLocalError: local variable 'n' referenced before assignment
Sporočilo je jasno - n
poskušamo uporabljati ("referencirati") preden jih
karkoli priredimo. Razumemo pa tudi ime napake, UnboundLocalError
- gre za
lokalno ime, ki pa še ni na nič vezano.
Obvozi mimo pravil
Napišimo funkcijo indeks(s, x)
, ki dobi seznam s
in vrednost x
ter vrne
indeks tega elementa v seznamu. Recimo, da smemo predpostaviti, da seznam v
resnici vsebuje ta element. Pri tem ne bomo uporabili očitne rešitve -
def indeks(s, x):
return s.index(x)
Ali skoraj enako očitne (a seveda bistveno počasnejše):
def indeks(s, x):
for i, e in enumerate(s):
if e == x:
return i
Naredili bomo nekaj neumnega: v neskončni zanki bomo naključno žrebali indekse, preverili ali je element s tem indeksom enak iskanemu, in ga v tem primeru vrnili.
def indeks(s, x):
from random import randint
while True:
i = randint(0, len(s) - 1)
if s[i] == x:
return i
Mimogrede, kako smo uvozili randint
? Lahko po takšnem uvozu uporabljamo
modul random
? Ne: from random import randint
veže ime randint
na
istoimensko funkcijo iz tega modula. Nič drugega. Modul random
je sicer v
resnici uvožen, vendar ne moremo do njega (razen, če poznamo kakšne stranske
poti :), ker nanj ni vezano nobeno ime.
Lahko po takšnem uvozu uporabljamo funkcijo randint
tudi izven funkcije?
Ne. Ime randint
je vezano samo lokalno. Tako kot, recimo i
- tudi tega
vidimo le znotraj funkcije.
Recimo, da nas zanima, kako slaba je ta ideja: radi bi šteli, kolikokrat je bilo potrebno ponoviti zanko. Kumulativno: recimo, da bomo večkrat poklicali funkcijo. In funkcija naj še vedno vrača le indeks.
poskusov = 0
def indeks(s, x):
from random import randint
while True:
poskusov += 1
i = randint(0, len(s) - 1)
if s[i] == x:
return i
To ne deluje, javi pa prav zanimivo napako
poskusov += 1
UnboundLocalError: local variable 'poskusov' referenced before assignment
Prirejanje poskusov += 1
moramo dojemati kot poskusov = poskusov + 1
.
To pomeni, da je poskusov
lokalna spremenljivka - saj ji znotraj funkcije
prirejamo vrednost. Python poskuša izračunati poskusov + 1
, ugotovi, da
ime poskusov
še ni vezano na noben objekt in ... konec zabave.
To uredimo tako Pythonu povemo, da je poskusov
globalna spremenljivka.
Nekam (zanimivo: kamorkoli) v funkcijo napišemo global poskusov
. Zdaj
bo Python vedno iskal ime poskusov
(ali, če bo šlo za vezavo, vezal
poskusov
) v globalni imenski prostor.
poskusov = 0
def indeks(s, x):
from random import randint
global poskusov
while True:
poskusov += 1
i = randint(0, len(s) - 1)
if s[i] == x:
return i
s = list(range(1000))
for i in range(100):
indeks(s, 0)
print(poskusov / 100)
Če stokrat poiščemo ničlo in izpišemo poprečno število potrebnih poskusov, dobimo nekaj zanimivega.
999.84
Številka je sumljivo blizu 1000. Ne bo vedno tako blizu, vedno pa bo ... kar blizu. Vendar to sodi v nek drug predmet.
No, nihče nam ne brani raziskovati tega fenomena tudi tu. Zaprimo celoten program v funkcijo, ki ji podamo velikost seznama (npr. 1000) in vrne število poskusov, ki je v poprečju potrebno, da najdemo element 0 (ki je sicer vedno čisto na začetku, vendar funkcija tega žal ne ve :).
def izmeri(n):
poskusov = 0
def indeks(s, x):
global poskusov
from random import randint
while True:
poskusov += 1
i = randint(0, len(s) - 1)
if s[i] == x:
return i
s = list(range(n))
for i in range(100):
print(indeks(s, 0))
return poskusov / 100
print(izmeri(1000))
To ne deluje.
Zato, ker ne smemo pisati funkcij znotraj funkcij? Ne, to ni nič neobičajnega.
def indeks
veže ime indeks
na funkcijo. Vezava je lokalna: ime indeks
je
znano znotraj imenskega prostora funkcije izmeri
.
Če pozorno pogledamo, imamo zdaj opravka s tremi imenskimi prostori.
En je globalni: v njem je pravzprav le ena reč (poleg avtomatske navlake),
namreč funkcija izmeri
.
Poleg tega imamo še dve funkciji, torej dva imenska prostora. Imenski prostor
funkcije izmeri
vsebuje ... no, saj nam funkcija sama pove, če
- pred
return poskusov / 100
dodamoprint(locals())
- pobrišemo
poskusov += 1
, da program ne bo javil napake, še preden sploh kaj izpiše, - klic
izmeri(1000)
spremenimo vizmeri(5)
, da izpis ne bo predolg.
Izpiše se
{'i': 99, 'indeks': <function izmeri.<locals>.indeks at 0x103c39950>,
's': [0, 1, 2, 3, 4], 'poskusov': 507, 'n': 5}
Tretji imenski prostor je imenski prostor funkcije indeks
. Če pred return
dodamo print(globals())
, izvemo
{'randint': <bound method Random.randint of <random.Random object at 0x7faad180c618>>,
's': [0, 1, 2, 3, 4], 'i': 0, 'x': 0}
V katerem imenskem prostoru, z vidika indeks
je ime poskusov
? V lokalnem ne.
V globalnem pa tudi ne. Lahko potem sploh pridemo do tega imena? Lahko.
def izmeri(n):
poskusov = 0
def indeks(s, x):
nonlocal poskusov
from random import randint
while True:
poskusov += 1
i = randint(0, len(s) - 1)
if s[i] == x:
return i
s = list(range(n))
for i in range(100):
indeks(s, 0)
return poskusov / 100
print(izmeri(5))
Definicija nonlocal
pomeni, da imena ne želimo iskati med lokalnimi imeni.
Pač pa ga išče v najbližjem nelokalnem prostoru. Če imamo funkcijo znotraj
funkcije znotraj funkcije ... nadaljuje iskanje navzven, dokler ne pride do
imena.
Ne spreglejte, da gre tu za iskanje glede na bloke, ne glede na klice.
Če ima neka funkcija spremenljivko i
in pokliče drugo funkcijo, le-ta ne
more dostopati do i
-ja, kot da bi bil le-ta nelokalna spremenljivka.
def g():
nonlocal i
print(i)
def f():
i = 12
g()
f()
Tole ne javi le napake med izvajanjem: Python ob tem programu javi celo
sintaktično napako! Ob prevajanju programa ugotovi, da i
-ja ne more vezati
na nobeno nelokalno spremenljivko.
Tudi tole ne deluje:
i = 0
def g():
nonlocal i
print(i)
Nelokalna spremenljivka mora biti lokalna spremenljivka funkcije, znotraj
katere je definirana g
. Globalni i
ne more biti nelokalni.
Globalne in nelokalne spremenljivke niso nekaj, kar bi smel človek uporabljati rutinsko in brez slabe vesti. Posebej za globalne spremenljivke potrebujemo dober izgovor.
Imenski prostori modulov
Recimo, da smo zgornji blok kode za računanje popolnih števil
shranili v datoteko stevila.py. Odprimo Python in napišimo import stevila
.
Zgodi se nekaj zanimivega. Izpišejo se vsa popolna števila do 1000.
>>> import stevila
[6, 28, 496]
Modul stevila
se sicer obnaša kot vsi spodobni moduli, ima, recimo, funkcijo
delitelji
, ki jo lahko pokličemo, kot se pač kliče funkcije v modulih.
>>> stevila.delitelji(28)
[1, 2, 4, 7, 14]
Tega smo vajeni, to ni nič takšnega: do funkcij (in drugih reči), ki so v modulih, pridemo tako, da napišemo ime modula, piko, in ime funkcije (ali druge reči).
Zakaj je izpisal vsa popolna števila, je sicer jasno: zaradi print
a na koncu.
Da bomo o tem čisto prepričani, dodajmo na konec datoteke stevila.py
še
print("Dober dan")
Zaprimo Python, ga ponovno odprimo in ponovno uvozimo modul. (To je potrebno zato, ker Python vedno uvozi modul le enkrat, ob ponovnih uvažanjih pa se samo dela, da ga je ponovno uvozil. Točneje: veže ime na že uvoženi modul.)
>>> import stevila
[6, 28, 496]
Dober dan
Zdaj pa namesto print("Dober dan")
dodajmo nekaj zanimivejšega:
print(globals())
. Modul naj izpiše globalne spremenljivke.
Izpiše se nek grozen slovar. Par stvari sem pobrisal (no, ena od teh parih stvari je bila dolga nekaj zaslonov); pustil sem le, kar je zanimivo.
>>> import stevila
[6, 28, 496]
{'delitelji': <function delitelji at 0x101229378>,
'popolno': <function popolno at 0x1012e4158>,
'popolna_do': <function popolna_do at 0x1012e47b8>,
'vsota': <function vsota at 0x1012e46a8>,
'__name__': 'stevila'}
In zdaj napišimo
>>> globals()
{'stevila': <module 'stevila' from '/Users/janezdemsar/py2/01 - imenski prostori/stevila.py'>,
'__name__': '__main__'}
Obstajata torej dva globals()
: modul ima svoje globalne spremenljivke,
"program", ki ga poganjamo (ali ukazna vrstica), pa svoje.
Točneje: vsak modul ima svoj globalni imenski prostor.
Še točneje: "glavni program" je v bistvu modul.
Vsak modul ima svoje globalne spremenljivke. Ko modul stevila
pokliče
globals()
, dobi svoje globalne spremenljivke; prav zato lahko znotraj
modula stevila
, recimo v funkciji popolno
, pokliče kar delitelji
in ne
stevila.delitelji
(za kar bi moral, za začetek, uvoziti modul stevila
,
torej samega sebe, kar se morda ne bi dobro končalo).
Ko "program" pokliče globals()
, dobi svoje globalne spremenljivke.
Ena od globalnih spremenljivk, ki se je pojavila sama od sebe, je __name__
.
Ta je imela doslej vrednost __main__
. Poglejte, kakšno vrednost ima v
globalnih spremenljivkah modula stevila
:
{'delitelji': <function delitelji at 0x101229378>,
'popolno': <function popolno at 0x1012e4158>,
'popolna_do': <function popolna_do at 0x1012e47b8>,
'vsota': <function vsota at 0x1012e46a8>,
'__name__': 'stevila'}
Spremenljivka __name__
vsebuje ime modula, torej 'stevila'
.
In zdaj še enkrat poglejmo "prava" globalna imena.
{'stevila': <module 'stevila' from '/Users/janezdemsar/py2/01 - imenski prostori/stevila.py'>,
'__name__': '__main__'}
Glavni program je torej pravzaprav le modul z imenom __main__
. Lahko ga celo
uvozimo - kar je sicer neumno, vendar se da.
>>> x = 5
>>> import __main__
>>> __main__.x
5
Pika, .
, je operator za dostop do imen znotraj imenskih prostorov modulov
(in razredov in objektov).
Kje so shranjena imena znotraj imenskih prostorov modulov? No, to že vemo:
v slovarju. Do tega slovarja pridemo z globals()
- vendar le, če pokličemo
globals()
znotraj modula, katerega imenski prostor nas zanima.
Vsak modul ima poleg vseh najrazličnejših funkcij in drugih reči, ki jih
izvaža, tudi slovar z imenom __dict__
. Ta slovar ni nič drugega kot slovar
njegovih globalnih imen - se pravi, ime, za katera ta modul meni, da so
globalna.
>>> stevila.__dict__
{'delitelji': <function delitelji at 0x101229378>,
'popolno': <function popolno at 0x1012e4158>,
'popolna_do': <function popolna_do at 0x1012e47b8>,
'vsota': <function vsota at 0x1012e46a8>,
'__name__': 'stevila'}
Kar je za nas stevila.__dict__
je za modul stevila
slovar, ki ga vrača
globals()
.
Ko napišemo stevila.delitelji
, zahtevamo tisto, kar je v slovarju "globalnih"
imen modula stevila
shranjeno pod ključem delitelji.
>>> __main__.__dict__ is globals()
True