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

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

if __name__ == '__main__':
    x = 1

print x

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


person froadie    schedule 13.05.2010    source источник
comment
Еще одна причуда, о которой вы могли не знать: если приведенный выше оператор if не выполняется (например, __name__ не '__main__', например, когда вы импортируете модуль вместо его выполнения на верхнем уровне), тогда x никогда не будет привязан, и последующий оператор print x выдаст NameError: name 'x' is not defined.   -  person Santa    schedule 14.05.2010


Ответы (8)


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

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

person Luke Maurer    schedule 13.05.2010
comment
@ chandr3sh docs.python.org/3/tutorial/ - person Fakher Mokadem; 15.11.2019

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

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

use(x)

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

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

if False:
    x = 3
print(x)

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

person Eli Bendersky    schedule 13.05.2010

Область видимости в Python следует в следующем порядке:

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

  • Найдите объем любых включающих функций

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

  • Искать по встроенным модулям

(источник)

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

person Daniel G    schedule 13.05.2010

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

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

person Paul Stephenson    schedule 13.05.2010
comment
Классы не создают области видимости; локальная переменная в классе просто добавляется к классу при создании. - person chepner; 20.08.2015

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

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

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

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

person Skilldrick    schedule 13.05.2010

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

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

person Olivier Verdier    schedule 13.05.2010

вы выполняете этот код из командной строки, поэтому 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
person SilentGhost    schedule 13.05.2010

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

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

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

person cowang    schedule 27.01.2020