Какова область действия переменной, инициализированной в операторе if?

266

Я новичок в Python, так что это, вероятно, простой вопрос. Следующий код в файле (модуле) Python меня немного смущает:

if __name__ == '__main__':
    x = 1

print x

В других языках, на которых я работал, этот код выдает исключение, поскольку xпеременная является локальной для ifоператора и не должна существовать вне ее. Но этот код выполняется и печатает 1. Кто-нибудь может объяснить это поведение? Все переменные, созданные в модуле, глобальны / доступны для всего модуля?

froadie
источник
17
Еще одна особенность , вы не могли бы знать: если ifвыше утверждение не имеет места (то есть, __name__это не '__main__' , например , при импорте модуля вместо выполнения его верхнего уровня), то xникогда не были связаны, и последующее print xзаявление бросит NameError: name 'x' is not defined.
Санта

Ответы:

302

Переменные Python ограничены самой внутренней функцией, классом или модулем, в котором они назначены. Блоки управления, такие как ifи whileблоки, не учитываются, поэтому переменная, назначенная внутри, ifвсе еще находится в области видимости для функции, класса или модуля.

(Неявные функции, определенные выражением генератора или списком / набором / диктом , имеют значение, как и лямбда-выражения. Вы не можете вставить оператор присваивания ни в один из них, но лямбда-параметры и forцели предложения являются неявным присваиванием.)

Люк Маурер
источник
1
@ chandr3sh docs.python.org/3/tutorial/…
Фахер Мокадем
105

Да, они находятся в одной и той же «локальной области видимости», и на самом деле такой код распространен в Python:

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

use(x)

Обратите внимание, что xон не объявлен или не инициализирован перед условием, как, например, в C или Java.

Другими словами, Python не имеет областей действия на уровне блоков. Будьте осторожны с примерами, такими как

if False:
    x = 3
print(x)

что явно вызовет NameErrorисключение.

Эли Бендерский
источник
42

Область действия в python следует этому порядку:

  • Поиск в локальной области

  • Поиск в объеме любых вмещающих функций

  • Поиск в глобальном масштабе

  • Поиск встроенных

( источник )

Заметь if и другие циклические / ветвящиеся конструкции не перечислены - только классы, функции и модули обеспечивают область действия в Python, поэтому все, что объявлено в ifблоке, имеет ту же область, что и все, что объявлено вне блока. Переменные не проверяются во время компиляции, поэтому другие языки выдают исключение. В Python, пока переменная существует в то время, когда вы в ней нуждаетесь, исключение не будет выдано.

Даниэль Г
источник
9

Как сказал Илай, Python не требует объявления переменных. В Си вы бы сказали:

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

но в Python объявление неявно, поэтому, когда вы присваиваете x, оно объявляется автоматически. Это потому, что Python динамически типизирован - он не будет работать на статически типизированном языке, потому что в зависимости от используемого пути переменная может использоваться без объявления. Это будет обнаружено во время компиляции на статически типизированном языке, но с динамически типизированным языком это разрешено.

Единственная причина, по которой статически типизированный язык ограничен необходимостью объявлять переменные вне ifоператоров из-за этой проблемы. Охватите динамику!

Skilldrick
источник
9

В отличие от таких языков, как C, переменная Python находится в области действия всей функции (или класса, или модуля), где она появляется, а не только в самом внутреннем «блоке». Это как если бы вы объявили int xв верхней части функции (или класса, или модуля), за исключением того, что в Python вам не нужно объявлять переменные.

Обратите внимание, что существование переменной xпроверяется только во время выполнения - то есть, когда вы попадаете в print xоператор. Если __name__не равны"__main__" , то вы получите исключение: NameError: name 'x' is not defined.

Пол Стивенсон
источник
Классы не создают область видимости; «локальная» переменная в классе просто добавляется к указанию класса при создании.
chepner
3

Да. Это также верно для forобъема. Но не функции, конечно.

В вашем примере: если условие в ifвыражении ложно, оно xне будет определено.

Оливье Вердиер
источник
2

Вы выполняете этот код из командной строки, поэтому ifусловия верны и xустановлены. Для сравнения:

>>> 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
источник
0

И обратите внимание, что поскольку типы Python проверяются только во время выполнения, вы можете иметь такой код:

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

Но мне трудно думать о других способах работы кода без ошибок из-за проблем с типами.

cowang
источник