Qual é o escopo de uma variável inicializada em uma instrução if?

266

Eu sou novo no Python, então essa é provavelmente uma questão de escopo simples. O código a seguir em um arquivo Python (módulo) está me confundindo um pouco:

if __name__ == '__main__':
    x = 1

print x

Em outros idiomas em que trabalhei, esse código geraria uma exceção, pois a xvariável é local para oif instrução e não deveria existir fora dela. Mas esse código é executado e imprime 1. Alguém pode explicar esse comportamento? Todas as variáveis ​​criadas em um módulo são globais / disponíveis para todo o módulo?

froadie
fonte
17
Outra peculiaridade que você pode não estar ciente: se a ifafirmação acima não é verdadeira (ou seja, __name__é não '__main__' , por exemplo, quando você importa o módulo em vez de executá-lo de nível superior), então xnunca foram ligados, e da subsequente print xdeclaração jogará a NameError: name 'x' is not defined.
Papai

Respostas:

302

As variáveis ​​Python têm o escopo definido para a função, classe ou módulo mais interno ao qual são atribuídos. Blocos de controle como ife whileblocos não contam, portanto, uma variável atribuída dentro de umif ainda tem escopo definido para uma função, classe ou módulo.

(Funções implícitas definida por um gerador de expressão ou lista / set / dict compreensão fazer contagem, assim como expressões lambda. Você não pode encher uma declaração de atribuição em qualquer um desses, mas os parâmetros lambda e foralvos cláusula são atribuição implícita.)

Luke Maurer
fonte
1
@ chandr3sh docs.python.org/3/tutorial/…
Fakher Mokadem 15/11/19
105

Sim, eles estão no mesmo "escopo local" e, na verdade, códigos como este são comuns no Python:

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

use(x)

Observe que xnão é declarado ou inicializado antes da condição, como seria em C ou Java, por exemplo.

Em outras palavras, o Python não possui escopos no nível do bloco. Tenha cuidado, porém, com exemplos como

if False:
    x = 3
print(x)

o que levantaria claramente uma NameErrorexceção.

Eli Bendersky
fonte
42

O escopo em python segue esta ordem:

  • Pesquise o escopo local

  • Pesquise o escopo de quaisquer funções anexas

  • Pesquise o escopo global

  • Pesquise os built-ins

( fonte )

Observe que ife outras construções de loop / ramificação não estão listadas - apenas classes, funções e módulos fornecem escopo no Python; portanto, qualquer coisa declarada em um ifbloco tem o mesmo escopo que qualquer coisa desclassificada fora do bloco. As variáveis ​​não são verificadas no momento da compilação, e é por isso que outros idiomas lançam uma exceção. Em python, desde que a variável exista no momento em que você precisar, nenhuma exceção será lançada.

Daniel G
fonte
9

Como Eli disse, o Python não requer declaração de variáveis. Em C você diria:

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

mas na declaração Python está implícita, portanto, quando você atribui x, ele é automaticamente declarado. É porque o Python é digitado dinamicamente - não funcionaria em uma linguagem estaticamente digitada, porque dependendo do caminho usado, uma variável pode ser usada sem ser declarada. Isso seria detectado no momento da compilação em um idioma estaticamente digitado, mas com um idioma digitado dinamicamente é permitido.

A única razão pela qual uma linguagem de tipo estaticamente é limitada a ter que declarar variáveis ​​fora das ifinstruções devido a esse problema. Abrace a dinâmica!

Skilldrick
fonte
9

Diferente de linguagens como C, uma variável Python está no escopo de toda a função (ou classe ou módulo) em que aparece, não apenas no "bloco" mais interno. É como se você declarasseint x na parte superior da função (ou classe ou módulo), exceto que no Python você não precisa declarar variáveis.

Observe que a existência da variável xé verificada apenas no tempo de execução - ou seja, quando você chega à print xinstrução. Se __name__não igual "__main__", então você gostaria de obter uma exceção: NameError: name 'x' is not defined.

Paul Stephenson
fonte
Classes não criam um escopo; uma variável "local" em uma classe é simplesmente adicionada ao comando da classe na criação.
chepner
3

Sim. Também é verdade para o forescopo. Mas não funciona, é claro.

No seu exemplo: se a condição na ifinstrução for falsa, xela não será definida.

Olivier Verdier
fonte
2

você está executando esse código na linha de comando, portanto, as ifcondições são verdadeiras e xestão definidas. Comparar:

>>> 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
fonte
0

E observe que, como os tipos Python são verificados apenas no tempo de execução, você pode ter códigos como:

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

Mas estou tendo problemas para pensar em outras maneiras pelas quais o código funcionaria sem erros devido a problemas de tipo.

cowang
fonte