Jaki jest związek między zakresem a przestrzeniami nazw w Pythonie?

12

W wielu zasobach stwierdziłem, że „zakres” i „przestrzenie nazw” są używane zamiennie, co wydaje się nieco mylące, ponieważ oznaczają różne rzeczy.

  • Zakres określa region kodu, w którym dostępna jest nazwa.
  • Reguła LEGB określa sposób wyszukiwania nazw.
  • Przestrzeń nazw to miejsce, w którym wyszukujesz nazwiska.

Potem czytam:

  • „nazwy są powiązane z przestrzenią nazw zgodnie z miejscem, w którym zostały przypisane ...” (moim zdaniem dotyczy to zakresów w zakresie leksykalnym).
  • „funkcje dodają dodatkową warstwę przestrzeni nazw do twoich programów” [ ref. ] (czy nie dodają dodatkowego zasięgu lokalnego?)
  • „wszystkie nazwy przypisane w definicji funkcji są umieszczane w zasięgu lokalnym (przestrzeń nazw powiązana z wywołaniem funkcji).”
  • „zakres globalny - czyli przestrzeń nazw, w której zmienne utworzone (przypisane) na najwyższym poziomie pliku modułu są aktywne”.

* wszystkie cytaty pochodzą z nauki Pythona 5. edycja ch17

Czy przestrzenie nazw w Pythonie są zaimplementowane w zakresach? Czy to to samo? Czy ktoś może mnie oświecić?

Nikos
źródło
1
Czy możesz podać referencje do cytatów - mógłbym znaleźć jeden, ale nie drugi.
jonrsharpe
1
Przestrzenie nazw są tylko jednym rodzajem zakresu. Zobacz stackoverflow.com/questions/291978/...
Robert Harvey

Odpowiedzi:

16

Nazw jest słownikiem, mapowanie nazwy (ciągami znaków) do wartości. Kiedy wykonujesz zadanie, na przykład a = 1, mutujesz przestrzeń nazw. Kiedy tworzysz odwołanie, na przykład print(a)Python przegląda listę przestrzeni nazw, aby spróbować znaleźć taką z nazwą jako kluczem.

A zakres określa, które nazw będą wyglądały i w jakiej kolejności. Zakres każdego odwołania zawsze zaczyna się w lokalnej przestrzeni nazw i przesuwa na zewnątrz, aż osiągnie globalną przestrzeń nazw modułu, zanim przejdzie do builtins(przestrzeni nazw, która odwołuje się do predefiniowanych funkcji i stałych Pythona, takich jak rangei getattr), która jest końcem linii .

Wyobraź sobie, że masz funkcję o nazwie inner, zagnieżdżoną w nazwie funkcji globalnej outeri innerzawiera ona odwołanie do nazwy. Python najpierw szuka w innerprzestrzeni nazw. Jeśli nie ma tam nazwy, Python następnie sprawdza outerprzestrzeń nazw. Jeśli to się nie powiedzie, Python wypróbuje globalprzestrzeń nazw modułu , a następnie builtinprzestrzeń nazw, ostatecznie wyrzucając a, NameErrorjeśli nazwa nie zostanie znaleziona.

Kiedy mówimy, że xznajduje się w przestrzeni nazw funkcji, mamy na myśli, że jest ona zdefiniowana lokalnie w obrębie funkcji. Kiedy mówimy, że xjest w zakresie funkcji, mamy na myśli xto , że znajduje się w przestrzeni nazw funkcji lub w dowolnej zewnętrznej przestrzeni nazw, w której jest zagnieżdżona przestrzeń nazw funkcji.

Za każdym razem, gdy definiujesz funkcję, tworzysz nową przestrzeń nazw i nowy zakres. Przestrzeń nazw to nowy lokalny skrót nazw. Zakres jest implikowanym łańcuchem przestrzeni nazw, który rozpoczyna się w nowej przestrzeni nazw, a następnie przechodzi przez dowolne zewnętrzne przestrzenie nazw (zewnętrzne zakresy), aż do globalnej przestrzeni nazw (zakres globalny) i do wbudowanych.

Terminy mogą być używane prawie zamiennie, ale nie dlatego, że oznaczają to samo; to dlatego, że bardzo się pokrywają w tym, co sugerują.

Carl Smith
źródło
3
„Pojęć można używać prawie zamiennie, ale to nie dlatego, że oznaczają to samo; to dlatego, że w dużym stopniu pokrywają się w tym, co sugerują”.
Nikos,
2
Ta odpowiedź jest dobra w duchu, ale w szczegółach błędna. Klasy w Pythonie nie wprowadzają nowej przestrzeni nazw, dlatego atrybuty klasy muszą być kwalifikowane nazwą klasy i dlatego atrybuty instancji muszą być kwalifikowane nazwą instancji. Poziomy przestrzeni nazw w Pythonie od wewnętrznej do zewnętrznej są Lokalne, Załączające, Globalne i Wbudowane. Klasę można zdefiniować na dowolnym z tych poziomów, ale członkowie klasy muszą zawsze mieć kwalifikacje.
Rob Smallshire
Masz rację. Klasy nie działają tak, jak powiedziałem. Myślałem, że tworzą zakres leksykalny jak funkcję, ale nie robią tego. Zaktualizuj odpowiedź, jeśli masz czas, w przeciwnym razie zrobię to w pewnym momencie. Dzięki.
Carl Smith
1
+1 Znakomita odpowiedź, tak oszczędnie ujmująca taką subtelność. Uważam to za bardzo pomocne, dziękuję!
poszukujący
1
„Przestrzeń nazw to skrót nazw, par wartości, bardzo podobny do słownika Pythona” - Jestem prawie pewien, że przestrzenie nazw przechowywane jako słowniki Pythona. Na przykład możesz edytować globalną przestrzeń nazw, wywołując globals (), co pozwala bezpośrednio modyfikować słownik w celu powiązania obiektów i nazw: na przykład globals () [name] = "object". W przeciwnym razie świetna odpowiedź.
Evan Rosica,
4

Jest doskonały artykuł na Python nazw tutaj . Aby zacytować odpowiednią część, aby odpowiedzieć na pytanie dotyczące odniesienia między zakresami i przestrzeniami nazw:

Zakres odnosi się do regionu programu, z którego można uzyskać dostęp do przestrzeni nazw bez prefiksu.

Wyobraź sobie na przykład prosty program do walcowania matryc:

import random  # 'random' is in module namespace

def roll(sides=6):  # 'roll' is in module namespace, 'sides' is in roll's
    return random.randint(1, sides)  # both 'random' and 'sides' are in scope here

# but sides can't be accessed out here 

roll ma własną przestrzeń nazw , ale nazwy w przestrzeni nazw modułu równieżobjęte zakresem .

jonrsharpe
źródło
@CarlSmith zauważa, że wczesna dokumentacja Pythona mówi to samo: „Zakres jest regionem tekstowym programu Python, w którym przestrzeń nazw jest bezpośrednio dostępna.” Bezpośrednio dostępne ”oznacza tutaj, że niekwalifikowane odniesienie do nazwy próbuje znaleźć nazwę w przestrzeni nazw. ”
jonrsharpe
@CarlSmith, oprócz dodatkowego zakresu nielokalnego / obejmującego, czy tak wiele się zmieniło? Myślę, że mówimy to samo - przestrzeń nazw zawiera nazwy i wartości, a zakres informuje, które przestrzenie nazw są dostępne.
jonrsharpe
Usunąłem moje stare komentarze.
Carl Smith