Zanurkuj w Pythonie/locals i globals: Różnice pomiędzy wersjami

Usunięta treść Dodana treść
Piotr (dyskusja | edycje)
koniec tłumaczenia
Robwolfe (dyskusja | edycje)
Nie podano opisu zmian
Linia 3:
== <tt>locals</tt> i <tt>globals</tt> ==
 
Odejdźmy teraz na minutkę od przetwarzania HTML-ua. Porozmawiajmy o tym, jak Python obchodzi się ze zmiennymi. Python posiada dwadwie wbudowane funkcje, <tt>locals</tt> i <tt>globals</tt>, które pozwalają nam uzyskać w słownikowy sposób dostęp do zmiennych lokalnych i globalnych.
 
Pamiętasz <tt>locals</tt>? Pierwszy raz zobaczyłeś to tutaj:
def unknown_starttag(self, tag, attrs):
strattrs = "".join([' %s="%s"' % (key, value) for key, value in attrs])
self.pieces.append("<%(tag)s%(strattrs)s>" % locals())
 
Nie, czekaj, nie mogłeśmożesz jeszcze się uczyć o <tt>locals</tt>. Najpierw, musisz nauczyć się, czym są przestrzenie nazw. Przedstawimy teraz trochę suchego materiału, lecz ważnego, dlatego też zachowaj uwagę.
 
Python korzysta z czegoś, co się nazywa przestrzenią nazw (ang. ''namespace''), aby śledzić zmienne. Przestrzeń nazw jest właśniewłaściwie jak słowniksłownikiem, gdzie kluczami są nazwy zmiennezmiennych, a wartościami słownika są wartości tych zmiennych. Właściwie możesz dostać się do przestrzeni nazw jak do Pythonowego słownika, co zresztą zobaczymy za chwilkę.
 
Z dowolnego miejsca Pythonowego programu mamy dostęp do kliku przestrzeni nazw. Każda funkcja posiada własną przestrzeń nazw, nazywaną ''lokalną przestrzenią nazw'', a która śledzi zmienne funkcji, włączając w to jej argumenty i lokalnie zdefiniowane zmienne. Każdy moduł posiada własną przestrzeń nazw, nazwaną ''globalną przestrzenią nazw'', a która śledzi zmienne modułu, włączając w to funkcje, klasy i inne zaimportowane moduły, a także zmienne zdefiniowane w tym module i stałe. Jest także wbudowana przestrzeń nazw, dostępna z każdego modułu, a która przechowuje funkcje wbudowane i wyjątki.
 
Kiedy pewna linia kodu pyta się o wartość zmiennej <tt>x</tt>, Python przeszuka wszystkie przestrzenie nazw, aby znaleść ją, w poniższym porządku:
Linia 21:
# wbudowana przestrzeń nazw namespace - globalna dla wszystkich modułów. Ponieważ jest to ostatnia deska ratunku, Python przyjmie, że <tt>x</tt> jest nazwą wbudowanej funkcji lub zmiennej.
 
Jeśli Python nie znajdzie <tt>x</tt> w żadnej z tych przestrzeni nazw, poddaje się i wyrzuciwyrzuca wyjątek NameError z wiadomością ''„There is no variable named 'x'”'', który zobaczyliśmy w ''Przykładzie 3.18'', „Odwoływanie się do niezdefiniowanej zmiennej”, lecz nie jesteś w stanie ocenić, jak Python zadziała, zanim dostaniesz ten błąd.
 
{{Uwaga|
Python 2.2 wprowadził subtelną, a zarazem ważną zmianę, którektóra wpływa na porządek przeszukiwania przestrzeni nazw: zagnieżdżonazagnieżdżone przestrzeńprzestrzenie nazw (ang. ''nested scope''). W wersjach wcześniejszych niż 2.2, kiedy odwoływałoodwołamy się do zmiennej wewnątrz zagnieżdżonej funkcji lub funkcji lambda, Python będzie szukał tej zmiennej w bieżącej przestrzeni nazw danej funkcji (zagnieżdżonej lub lambda), a następnie w przestrzeni nazw modułu. Python 2.2 będzie szukał zmiennej w bieżącej przestrzeni nazw danej funkcji (zagnieżdżonej lub lambda), następnie w przestrzeni nazw nadrzędnej funkcji, a potem w przestrzeni nazw modułu.
}}
 
Zmieszałeś się? Nie panikuj! Jest to naprawdę cool. Podobnie, jak wiele rzeczy w Pythonie, przestrzenie nazw są bezpośrednio dostępne podczas wykonywania programu. Jak? Do lokalnej przestrzeni nazw mamy dostęp poprzez wbudowaną funkcję <tt>locals</tt>, a do globalna (na poziomie modułu) przestrzeń nazw jest dostępna poprzez wbudowaną funkcję <tt>globals</tt>.
 
'''Przykład 8.10. Wprowadzenie do <tt>locals</tt>'''
Linia 41:
 
# Funkcja <tt>foo</tt> posiada dwie zmienne w swojej lokalnej przestrzeni nazw: <tt>arg</tt>, której wartość jest przekazana do funkcji, a także <tt>x</tt>, która jest zdefiniowana wewnątrz funkcji.
# <tt>locals</tt> zwraca słownik par nazwa/wartość. Kluczami słownika są nazwy zmiennej,zmiennych aw którepostaci są napisaminapisów. Wartościami słownika są bieżące wartości tych zmiennych. Zatem wywołując <tt>foo</tt> z 7, wypiszemy słownik zawierający dwie lokalne zmienne tej funkcji, czyli <tt>arg</tt> (o wartości <tt>7</tt>) i <tt>x</tt> (o wartości <tt>1</tt>).
# Pamiętaj, Python jest dynamicznie typowany, dlatego też możemy w prosty sposób jako argument <tt>arg</tt>, przekazać napis. Funkcja (a także wywołanie <tt>locals</tt>) będą nadal działać jak należy. <tt>locals</tt> działa z wszystkimi zmiennymi dowolnych typów danych.
 
Linia 56:
print k, "=", v
 
# WłaściwieNa niewypadek czujeszgdybyś wystraszonysię wystraszył, pamiętaszpamiętaj, że widzieliśmy to już wcześniej. Funkcja <tt>globals</tt> zwraca słownik, którypo którym następnie iterujemy wykorzystując metodę <tt>items</tt> i wielozmienne przypisanie. Jedyną nową rzeczą jest funkcjefunkcja <tt>globals</tt>.
 
Teraz, uruchamiając skrypt z linii poleceń otrzymamy takie wyjście (twoje wyjście może się nieco różnić, zależnie od tego, na jakim systemie i gdzie zainstalowałeś Pythona):
Linia 70:
# <tt>SGMLParser</tt> został zaimportowany z <tt>sgmllib</tt>, wykorzystując <tt>from module import</tt>. Oznacza to, że został zaimportowany bezpośrednio do przestrzeni nazw modułu i w tym też miejscu jest.
# W przeciwieństwie do <tt>SGMLParser</tt>-a, <tt>htmlentitydefs</tt> został zaimportowany wykorzystując instrukcję <tt>import</tt>. Oznacza to, że moduł <tt>htmlentitydefs</tt> sam w sobie jest przestrzenią nazw, ale zmienna <tt>entitydefs</tt> wewnątrz <tt>htmlentitydefs</tt> już nie.
# Moduł ten definiuje jedną klasę, <tt>BaseHTMLProcessor</tt> i tutajoto on jest. Dodajmy, że ta wartość samąjest klasą jako taką, a nie jakąś specyficzną instancją tej klasy.
# Pamiętasz trik <tt>if __name__</tt>? Kiedy uruchamiamy moduł (zamiast importować go z innego modułu), to wbudowany atrybut <tt>__name__</tt> ma specjalną wartość, <tt>"__main__"</tt>. Ponieważ uruchomiliśmy ten moduł jako skrypt z linii poleceń, wartość <tt>__name__</tt> wynosi <tt>"__main__"</tt>, dlatego też zostanie wykonany mały kod testowy, który wypisuje <tt>globals</tt>.
 
{{Infobox|
KorzystająKorzystając z funkcji <tt>locals</tt> i <tt>globals</tt> możemy pobrać dynamicznie wartość dowolnej zmiennej, dzięki przekazaniu nazwy zmiennej w postaci napisu. Funkcjonalność ta jest analogiczna do <tt>getattr</tt>, która pozwala dostać się do dowolnej funkcji, dzięki przekazaniu jej nazwy w postaci napisu.
}}
 
Tutaj mamy inną ważną różnicę między funkcjami <tt>locals</tt> i <tt>globals</tt>, a o którychktórej powinieneś się dowiedzieć, zanim cię ukąsi. Jakkolwiek to i tak cię ukąsi, ale przynajmniej będziesz pamiętał, że się o tym uczyłeś.
 
'''Przykład 8.12. <tt>locals</tt> jest tylko do odczytu, a <tt>globals</tt> już nie'''
Linia 97:
# <tt>locals</tt> jest funkcją zwracającą słownik i w tym miejscu zmieniamy wartość w tym słowniku. Możesz myśleć, że wartość zmiennej <tt>x</tt> zostanie zmieniona na <tt>2</tt>, jednak tak nie jest. <tt>locals</tt> właściwie nie zwraca lokalnej przestrzeni nazw, zwraca jego kopię. Zatem zmieniając ją, nie zmieniamy wartości zmiennych w lokalnej przestrzeni nazw.
# Zostanie wypisane <tt>x= 1</tt>, a nie <tt>x= 2</tt>.
# Po tym, jak zostaliśmy poparzeni przez <tt>locals</tt>, możemy myśleć, że ta operacja nie zmieni wartości <tt>z</tt>, ale w rzeczywistości zmieni. you might think that this wouldn't change the value of z, but it does. W skutek wewnętrznych różnicachróżnic implementacyjnych <ref>Nie będziemy się wdawać w szczegóły</ref>, <tt>globals</tt> zwraca aktualną, globalną przestrzeń nazw, a nie jej kopię; całkowicie odwrotne zachowanie w stosunku do <tt>locals</tt>. Tak więc dowolna zmiana, zwróconego przez <tt>globals</tt> słownika, bezpośrednio wpływa na zmienne globalne.
# Wypisze <tt>z= 8</tt>, a nie <tt>z= 7</tt>.