Fuggveny globalis valtozo pythonban mikor kell?
Pelda:
a = 10
def demo():
global a
print a
Eszrevettem, hogy nehol ott is elerheto a globalis valtozo a programomban ha elhagyom a global kulcsszot. De nem mindig, van ahol kotelezo megadnom hogy global. Mitol fugghet ez?
Alapból a Python "névterek"-ből (namespace) áll és ezekben a névterekben találhatóak a változók, függvények, osztályok, stb, amik önmagában szintén saját névtereket képeznek.
Amikor azt írod hogy "a = 10", akkor a jelenlegi névtérben létrehozol (vagy felülírsz) egy "a" nevű változót (nevet) és 10-et adsz meg neki értéknek. Az "a" értéke sosem módosul, hanem felülíródik minden értékadásnál, mert a "=" operátor mindig új nevet hoz létre, így pl. overloadolni sem lehet azt.
Ha a demo függvényben (névtérben) azt írod hogy "a = 5" akkor a demo névtérben létrehoz egy "a" nevű változót. Ha te a globális névtérben akarod inkább használni az "a" változót akkor ezt meg kell mondani a programnak: ne a lokális névtérben hozd létre, hanem a globálisban. Erre való a global parancs.
Tehát itt 2 "a" változód lesz, egy lokális a demo névtérben és egy globális, az egyik 5 értékkel, a másik 10-el:
a=10
def demo():
__a=5
Itt viszont csak egy "a" változód (neved) lesz, a globális névtérben, 5 értékkel:
a=10
def demo():
__global a
__a=5
Az oka hogy elhagyhatod a global szót az az, hogy ha nem létrehozol el nevet értékadással hanem egy létezőre hivatkozol, akkor elkezdi keresni a program, hogy melyik névtérben lehet a hivatkozott név:
a = 10
def demo1():
__def demo2():
____print a
Itt a globális névtérben van egy "a" változó és a "demo1" függvény, aminek a névterében van egy "demo2" függvény ahonnan hivatkozunk az "a"-ra. Megnézi hogy a demo2-ben van e "a", mivel nincs, kijjebb lép, megnézi a demo1-ben hogy van e "a", nincs ezért még kijjebb lép, megnézi hogy a globális névtérben van e "a", van ezért azt használja.
Ha nem talál "a" nevet és már nem tud kijjebb lépni, "NameError" kivételt fogsz kapni, azaz nincs definiálva ilyen név.
Vigyázz, mert ha a demo1-ben is van "a", akkor arra fog hivatkozni és nem a globálisra, mert az "közelebb" van. Ha a globálist akarod használni helyette, akkor akkor itt is szólni kell a global kulcsszóval!
Python3-ban létezik egy olyan kulcsszó is hogy nonlocal.
Ez olyan mint a global, csak nem a global névtérben fogja módosítani (felülírni) a kérdéses nevet, hanem el kezdi keresni a nevet a lokális névterekben a fentebb vázolt módon és az első találatra fog hivatkozni.
Nem kell definiálni egy nevet a globális névtérben ahhoz hogy használhassuk a global kulcsszót.
a = 10
pontosan ugyan azt csinálja mint a
def demo():
__global a
__a = 10
demo()
azaz a globális névtérben létrehoz egy "a" nevet (és hozzáköti a 10-et).
Ha kíváncsi vagy a névterekre amúgy a dir() parancs listázza:
dir():
['__builtins__', '__doc__', '__name__', '__package__', 'a', 'demo1']
dir(a):
['__abs__', '__add__', '__and__', '__class__', '__cmp__', '__coerce__', '__delattr__', '__div__', '__divmod__', '__doc__', '__float__', '__floordiv__', '__format__', '__getattribute__', '__getnewargs__', '__hash__', '__hex__', '__index__', '__init__', '__int__', '__invert__', '__long__', '__lshift__', '__mod__', '__mul__', '__neg__', '__new__', '__nonzero__', '__oct__', '__or__', '__pos__', '__pow__', '__radd__', '__rand__', '__rdiv__', '__rdivmod__', '__reduce__', '__reduce_ex__', '__repr__', '__rfloordiv__', '__rlshift__', '__rmod__', '__rmul__', '__ror__', '__rpow__', '__rrshift__', '__rshift__', '__rsub__', '__rtruediv__', '__rxor__', '__setattr__', '__sizeof__', '__str__', '__sub__', '__subclasshook__', '__truediv__', '__trunc__', '__xor__', 'bit_length', 'conjugate', 'denominator', 'imag', 'numerator', 'real']
Lehet látni hogy az "a" nem csak változó hanem névtér is, és vannak függvényei amik szintén névtereket alkotnak (és minden függvénynek van __call__ névterük ami meghívódik ha meghívjuk a függvényt):
>>> a = 10
>>> a.__add__(3) #ez történik valójában amikor azt írjuk hogy a + 3
13
És ha korrektek akarunk lenni, akkor azt is el kell mondani hogy fentebb az történt hogy az "a" névhez kötöttük a 10 int típusú objektumot (névteret), tehát nem az "a" képzi a névteret, csak csak egy név, egy kötelék amivel hivatkozni lehet a hozzákötött névtérre. A névtér valójában maga az objektum: dir(10)
Csak azért írtam le ilyen hosszan mert sok kezdő beleesik abba a hibába hogy azt hiszik, a Python ugyan úgy működik mint a többi programozási nyelv (pointerek, változók, referenciák stb itt nem léteznek!) és ebből jönnek a bajok, nem értik később miért nem azt csinálja a program amit szerintük kéne. Jó ha az ember tisztában van a névterekkel és a Python működésével.
Kapcsolódó kérdések:
Minden jog fenntartva © 2024, www.gyakorikerdesek.hu
GYIK | Szabályzat | Jogi nyilatkozat | Adatvédelem | Cookie beállítások | WebMinute Kft. | Facebook | Kapcsolat: info(kukac)gyakorikerdesek.hu
Ha kifogással szeretne élni valamely tartalommal kapcsolatban, kérjük jelezze e-mailes elérhetőségünkön!