Globalne spremenljivke

Bližamo se koncu predavanj. Nekateri prihajate v programersko puberteto in vas bo morda začenjalo razganjati, zato je čas, da se očki pogovorijo s sinčki in mamice s hčerkami o tisti nerodni temi: o globalnih spremenljivkah.

Vsaka funkcija se mora sramežljivo brigati samo za svoje reči. (To zdaj v kontekstu onega zgoraj zveni čudno, zato bom nehal z metaforami.) Funkcija dobi vse podatke prek argumentov in vrne rezultate z return-om. V teoriji. V praksi funkcije pogosto "vidijo" tudi kaj, česar niso dobile prek argumentov. Če ne drugega, uporabljajo module, ki jih niso uvozile same. Poleg tega "vidijo" funkcije, kot so len in podobne. Ideala ni, ker bi bil nepraktičen. Pač pa se zmenimo za seznam stvari, ki se jih ne počne, od manj proti bolj prepovedanim:

  • Ni lepo, če funkcija bere vrednosti spremenljivk, definiranih izven nje. Ni pa take katastrofe, če to počnemo, posebej, kadar bi bila "pravilna" rešitev zelo nepraktična. Primer takšnega početja so vse funkcije v zapiskih iz rekurzije, saj berejo vrednosti iz slovarja rodovnik, ki ga niso dobile kot argument. Spremenljivka rodovnik je že primer globalne spremenljivke, ker je definirana zunaj vseh funkcij.
  • Ni posebej lepo, če funkcija dobi argument zato, da bi v njem vrnila rezultat. Primer bi bila funkcija, ki dobi prazen seznam zato, da ga napolni. Lepše je, če funkcija vrne seznam. Vendar je takšno početje včasih smiselno, kadar si funkcije podajajo nek seznam (ali kaj drugega), ki ga "dopolnjujejo".
  • Grdo je, če funkcija spreminja vrednosti globalnih spremenljivk. Primer tega bi bil, če bi funkcije iz zapiskov v rekurziji spreminjale slovar rodovnik - ohranile bi isti slovar, vendar bi vanj dodajale potomce.
  • Še bolj grdo in skoraj nesprejemljivo je, da funkcija prireja nove vrednosti globalnim imenom. Primer tega bi bila funkcija, ki spremenljivki (točneje: imenu) rodovnik priredi nek popolnoma nov slovar. V kombinaciji z branjem in shranjevanjem vrednosti globalnih spremenljivk to kar kliče po napakah, ki jih bo nemogoče najti, predvsem v večjih programih. To se ne dela. In to bomo delali v domači prednalogi, kar je razlog, da se o vsem skupaj sploh pogovarjamo. (Zakaj bomo potem to delali? Ker ne znamo drugače in ker bomo na predavanjih spoznali, način programiranja, s katerim se temu izognemo. To bo tudi razlika med prednalogo in pravo domačo nalogo.
  • Funkcija ne sme spreminjati vrednosti argumentov, če ni to točno tisto, kar se od nje pričakuje. Precej primerov tega ste videli v napačnih rešitvah domačih nalog.

Zdaj, ko veste, kaj se ne sme delati, vam lahko povem, kako se to naredi. Tule je funkcija, ki nekaj dela s svojimi lokalnimi spremenljivkami.

def f(): x = 1 y = 2 z = 3

Če jo pokličemo, priredi imenom x, y in z dve vrednosti, vendar ta imena po klicu funkcije ne obstajajo več.

>>> f() >>> x Traceback (most recent call last): File "<stdin>", line 1, in <module> NameError: name 'x' is not defined >>> y Traceback (most recent call last): File "<stdin>", line 1, in <module> NameError: name 'y' is not defined

Zdaj pa funkciji rečem, da sta imeni x in y mišljeni globalno.

def f(): global x, y x = 1 y = 2 z = 3

Zdaj poglejmo tole:

>>> x = 42 >>> f() >>> x 1 >>> y 2 >>> z Traceback (most recent call last): File "<stdin>", line 1, in <module> NameError: name 'z' is not defined

Spremenljivko x sem pred klicem funkcije postavil na 42. Ko je funkcija priredila x-u vrednost 1, se je prirejanje nanašalo na globalno ime x in ne na ime x znotraj funkcije - točneje, znotraj funkcije ni nobenega x, edini x, ki je, je zunanji x.

Tudi, ko je funkcija prirejala imenu y, je to zunanji y. Prej ga še ni bilo, zdaj pač je.

Ime z pa je lokalno ime.

Zadnja sprememba: četrtek, 26. december 2013, 15.39