2012-01-31 10 views
10

Weźmy następujący kod:"zmienna lokalna przywoływana przed przypisaniem" - tylko funkcje?

import something 

def Foo(): 
    something = something.SomeClass() 
    return something 

... to widocznie nie prawidłowy kod:

UnboundLocalError: local variable 'something' referenced before assignment 

... jako zmiennej lokalnej something jest tworzony, ale nie przypisano przed RHS z = jest oceniany . (Zobacz na przykład: this related answer's comment.) Wydaje mi się to nieco dziwne, ale na pewno pójdę z tym. Dlaczego jest następujący prawidłowy kod?

class Foo(object): 
    something = something.SomeClass() 

Moje zrozumienie było to, że wewnątrz class definicji był zasadniczo zakres:

apartament klasy jest następnie wykonywany w nowej ramce wykonania (patrz sekcja nazewnictwa i wiążące), stosując nowo utworzona lokalna przestrzeń nazw i oryginalna globalna przestrzeń nazw.

A więc dlaczego ten kod działa inaczej niż funkcja?

+0

"coś" wydaje się mieć więcej niż jedno znaczenie? – Johnsyweb

+0

@Johnsyweb: Tak, trochę. Ale w obu przypadkach ma to samo znaczenie więcej niż jedno. (A przynajmniej wszystkie dokumenty, które przeczytałem, wydają się tak mówić.) – Thanatos

Odpowiedz

4

Rozważmy następujący przykład, który może przyczynić się do wyjaśnienia tego:

import datetime 

class Foo(object): 
    datetime = datetime.datetime 

>>> datetime 
<module 'datetime' from '/usr/lib/python2.6/lib-dynload/datetime.so'> 
>>> Foo.datetime 
<type 'datetime.datetime'> 

Zauważ, że linia datetime = datetime.datetime faktycznie przypisanie do nazwy Foo.datetime, co nie jest niejednoznaczny z globalnym datetime (jak byłoby gdyby ten sam kod był w funkcji).

Podsumowując, ponieważ definicje klas tworzą nowy obszar nazw, a także nowy zakres, można bezpośrednio uzyskać dostęp do nazwy w zasięgu obejmującym i przypisać do tej samej nazwy w zakresie lokalnym.

+0

"Zauważ, że wiersz' datetime = datetime.datetime' faktycznie przypisuje nazwę 'Foo.datetime', który nie jest niejednoznaczny z globalnym 'datetime'" - Nie: przypisuje on nazwę 'datetime': Jeśli dodasz dwie instrukcje' print datetime', jedną przed 'datetime =' i jedną po, jak jest "datetime" w tym oświadczeniu * nie * niejednoznaczne, w jakiś sposób różni się od tych samych instrukcji w funkcji? – Thanatos

+0

@Thanatos - Tak, widzę, jak to jest niejasne. Próbowałem powiedzieć, że przestrzeń nazw stworzone przez klasę pozwala na jednoznaczny dostęp do globalnego i klasowego atrybutu z innych zakresów, ale masz rację, nadal istnieje niejasność w lokalnym zakresie klasy –

+0

Ale sedno pytania brzmi: jak to jest inaczej? niż to, co dzieje się w funkcji? Podajesz "ponieważ definicje klas tworzą nowy obszar nazw, a także nowy zakres" - czy funkcje nie tworzą zarówno nowej przestrzeni nazw, jak i nowego zakresu? - "masz bezpośredni dostęp do nazwy w obejmujący zakres "- mogę zrobić to w funkcji - "i przypisz do tej samej nazwy w zasięgu lokalnym" - Mogę to zrobić tylko w definicji klasy ... dlaczego? – Thanatos

6

Z python class documentation:

definicje Class miejsce kolejna nazw w zakresie lokalnym.

Szczególnym dziwactwem Pythona jest to, że - jeśli nie ma żadnego globalnego wyciągu - przypisania do nazw zawsze przechodzą w najbardziej wewnętrzny zakres. Przypisania nie kopiują danych - po prostu wiążą nazwy z obiektami. To samo dotyczy usuwania: instrukcja del x usuwa powiązanie x z przestrzeni nazw, do której odwołuje się zasięg lokalny. W rzeczywistości wszystkie operacje wprowadzające nowe nazwy korzystają z zasięgu lokalnego: w szczególności instrukcje importu i definicje funkcji wiążą nazwę modułu lub funkcji w zasięgu lokalnym. (Globalny Oświadczenie może być stosowane w celu wskazania, że ​​poszczególne zmienne żyć w zasięgu globalnym.)

Więc wewnątrz funkcji (lub zakres) przypisanie tworzy lokalną zmienną niezwiązaną które jest dostępne, zanim zostanie ona związana, natomiast w definicji klasy tworzy wpis w słowniku "przestrzeni nazw" tej klasy podczas przypisywania, umożliwiając rozdzielczość something na zewnętrzną przestrzeń nazw (przestrzeń nazw modułu).

Powiązane problemy