Jaki jest zakres zmiennej zainicjowanej w instrukcji if?

266

Jestem nowy w Pythonie, więc jest to prawdopodobnie proste pytanie dotyczące zakresu. Poniższy kod w pliku (module) Pythona nieco mnie dezorientuje:

if __name__ == '__main__':
    x = 1

print x

W innych językach, w których pracowałem, ten kod zgłosiłby wyjątek, ponieważ xzmienna jest lokalna dla ifinstrukcji i nie powinna istnieć poza nią. Ale ten kod wykonuje i drukuje 1. Czy ktoś może wyjaśnić to zachowanie? Czy wszystkie zmienne są tworzone w module globalnym / dostępne dla całego modułu?

froadie
źródło
17
Kolejne dziwactwo, o którym możesz nie wiedzieć: jeśli ifpowyższa instrukcja nie jest prawdziwa (tzn. Nie__name__ jest , na przykład podczas importowania modułu zamiast wykonywania go na najwyższym poziomie), to nigdy nie zostanie powiązany, a kolejna instrukcja rzuci . '__main__'xprint xNameError: name 'x' is not defined
Święty Mikołaj

Odpowiedzi:

301

Zmienne w języku Python obejmują najbardziej wewnętrzną funkcję, klasę lub moduł, do którego są przypisane. Bloki kontrolne, takie jak ifi whilebloki, nie liczą się, więc zmienna przypisana w obrębie ifjest nadal objęta funkcją, klasą lub modułem.

(Funkcje niejawne zdefiniowane przez wyrażenie generatora lub rozumienie list / set / dict liczone, podobnie jak wyrażenia lambda. Nie można wstawić instrukcji przypisania do żadnego z nich, ale parametry lambda i forcele klauzuli są domyślnie przypisane.)

Luke Maurer
źródło
1
@ chandr3sh docs.python.org/3/tutorial/…
Fakher Mokadem
105

Tak, są w tym samym „zasięgu lokalnym” i tak naprawdę taki kod jest powszechny w Pythonie:

if condition:
  x = 'something'
else:
  x = 'something else'

use(x)

Zauważ, że xnie jest zadeklarowany ani zainicjowany przed warunkiem, tak jak na przykład w C lub Java.

Innymi słowy, Python nie ma zasięgów na poziomie bloku. Uważaj jednak na przykłady takie jak

if False:
    x = 3
print(x)

co wyraźnie podniosłoby NameErrorwyjątek.

Eli Bendersky
źródło
42

Zakres w python ma następującą kolejność:

  • Wyszukaj zasięg lokalny

  • Przeszukaj zakres dowolnych funkcji obejmujących

  • Wyszukaj zasięg globalny

  • Wyszukaj wbudowane

( źródło )

Zauważ, że ifi inne konstrukcje pętli / rozgałęzień nie są wymienione - tylko klasy, funkcje i moduły zapewniają zakres w Pythonie, więc wszystko zadeklarowane w ifbloku ma taki sam zasięg jak wszystko, co zostało zadeklarowane poza tym blokiem. Zmienne nie są sprawdzane podczas kompilacji, dlatego inne języki zgłaszają wyjątek. W Pythonie, dopóki zmienna istnieje w wymaganym momencie, żaden wyjątek nie zostanie zgłoszony.

Daniel G.
źródło
9

Jak powiedział Eli, Python nie wymaga deklaracji zmiennej. W C powiedziałbyś:

int x;
if(something)
    x = 1;
else
    x = 2;

ale w Pythonie deklaracja jest niejawna, więc po przypisaniu do x jest automatycznie deklarowana. Jest tak, ponieważ Python jest dynamicznie wpisywany - nie działałby w języku o typie statycznym, ponieważ w zależności od użytej ścieżki zmienna może być używana bez deklaracji. Zostałoby to wychwycone podczas kompilacji w języku o typie statycznym, ale w języku o typie dynamicznym jest to dozwolone.

Jedyny powód, dla którego język o typie statycznym ogranicza się do konieczności deklarowania zmiennych poza ifinstrukcjami z powodu tego problemu. Uwzględnij dynamikę!

Skilldrick
źródło
9

W przeciwieństwie do języków takich jak C, zmienna Pythona jest objęta zakresem całej funkcji (lub klasy lub modułu), w której się pojawia, a nie tylko w najbardziej „wewnętrznym” bloku. To tak, jakbyś zadeklarował int xna górze funkcji (lub klasy, lub modułu), tyle że w Pythonie nie musisz deklarować zmiennych.

Zauważ, że istnienie zmiennej xjest sprawdzane tylko w czasie wykonywania - to znaczy po przejściu do print xinstrukcji. Jeśli __name__nie są równe "__main__"wtedy można uzyskać wyjątek: NameError: name 'x' is not defined.

Paul Stephenson
źródło
Klasy nie tworzą zakresu; zmienna „lokalna” w klasie jest po prostu dodawana do dyktatury klasy podczas tworzenia.
chepner,
3

Tak. Dotyczy to również forzakresu. Ale oczywiście nie działa.

W twoim przykładzie: jeśli warunek w ifinstrukcji jest fałszywy, xnie zostanie zdefiniowany.

Olivier Verdier
źródło
2

wykonujesz ten kod z wiersza poleceń, dlatego ifwarunki są spełnione i xustawione. Porównać:

>>> if False:
    y = 42


>>> y
Traceback (most recent call last):
  File "<pyshell#6>", line 1, in <module>
    y
NameError: name 'y' is not defined
SilentGhost
źródło
0

I zauważ, że ponieważ typy Pythona są sprawdzane tylko w czasie wykonywania, możesz mieć kod taki jak:

if True:
    x = 2
    y = 4
else:
    x = "One"
    y = "Two"
print(x + y)

Ale mam problem z myśleniem o innych sposobach działania kodu bez błędu z powodu problemów z typem.

cowang
źródło