Qual é a relação entre escopo e namespaces no Python?

12

Em muitos recursos, achei "escopo" e "namespaces" usados ​​de forma intercambiável, o que parece um pouco confuso, pois significa coisas diferentes.

  • Escopo define a região do código em que um nome está disponível.
  • A regra LEGB define a maneira como os nomes são pesquisados.
  • Namespace é um local onde você procura nomes.

Então eu li:

  • "os nomes são vinculados a um espaço de nome de acordo com o local onde estão atribuídos ..." (que eu acredito que é o acordo com os escopos no escopo lexical).
  • "funções adicionam uma camada extra de namespace aos seus programas" [ ref. ] (eles não adicionam um escopo local extra?)
  • "todos os nomes atribuídos dentro de uma definição de função são colocados no escopo local (o espaço para nome associado à chamada de função)."
  • "escopo global - ou seja, um espaço para nome no qual vivem as variáveis ​​criadas (atribuídas) no nível superior do arquivo do módulo."

* todas as citações são do aprendizado de python 5a edição ch17

Os namespaces no Python são da maneira que os escopos são implementados? Eles são a mesma coisa? Alguém pode me esclarecer?

Nikos
fonte
1
Você poderia fornecer referências para as citações - eu poderia encontrar uma, mas não a outra.
jonrsharpe
1
Namespaces são apenas um tipo de escopo. Veja stackoverflow.com/questions/291978/…
Robert Harvey

Respostas:

16

Um espaço para nome é um dicionário, mapeando nomes (como cadeias) para valores. Quando você faz uma tarefa a = 1, você está mudando um espaço para nome. Quando você faz uma referência, por exemplo print(a), o Python examina uma lista de espaços para nome para tentar encontrar um com o nome como chave.

Um escopo define em quais namespaces serão procurados e em que ordem. O escopo de qualquer referência sempre começa no namespace local e se move para fora até atingir o namespace global do módulo, antes de passar para o builtins(o namespace que faz referência às funções e constantes predefinidas do Python, como rangee getattr), que é o fim da linha .

Imagine que você tenha uma função nomeada inner, aninhada em uma função global denominada outere innercontenha uma referência a um nome. O Python procura pela primeira vez no innerespaço para nome. Se o nome não estiver lá, o Python procurará no outerespaço para nome. Se isso falhar, o Python tenta o globalespaço para nome do módulo e , em seguida, o builtinespaço para nome, eventualmente lançando um NameErrorse o nome não for encontrado.

Quando dizemos que xestá no espaço de nomes de uma função, queremos dizer que ela é definida lá, localmente dentro da função. Quando dizemos que xestá no escopo da função, queremos dizer que xestá no namespace da função ou em qualquer um dos namespaces externos em que o namespace da função está aninhado.

Sempre que você define uma função, cria um novo espaço para nome e um novo escopo. O espaço para nome é o novo hash local de nomes. O escopo é a cadeia implícita de espaços para nome que inicia no novo espaço para nome e, em seguida, percorre qualquer espaço para nome externo (escopo externo), até o espaço para nome global (escopo global) e para os recursos internos.

Os termos podem ser usados ​​quase de forma intercambiável, mas não é porque eles significam a mesma coisa; é porque eles se sobrepõem muito ao que implicam.

Carl Smith
fonte
3
"Os termos podem ser usados ​​quase de forma intercambiável, mas não é porque eles significam a mesma coisa; é porque eles se sobrepõem muito ao que implicam".
Nikos
2
Esta resposta é correta em espírito, mas errada em detalhes. As classes no Python não introduzem um novo espaço para nome, e é por isso que os atributos da classe devem ser qualificados com o nome da classe e por que os atributos da instância devem ser qualificados com o nome da instância. Os níveis de espaço para nome no Python, de interno para externo, são Local, Anexo, Global e Integrado. Uma classe pode ser definida em qualquer um desses níveis, mas os membros de uma classe sempre devem ser qualificados.
Rob Smallshire
Você está certo. As aulas não funcionam como eu disse. Eu estava pensando que eles criam um escopo lexical como uma função, mas eles não. Atualize a resposta se tiver tempo, caso contrário, eu o farei em algum momento. Obrigado.
Carl Smith
1
+1 Resposta brilhante, encapsulando essa sutileza de maneira econômica. Achei isso muito útil, obrigado!
Decker
1
"Um espaço para nome é um hash de nome, pares de valores, muito parecido com um dicionário Python" - tenho certeza de que os espaços para nome são armazenados como dicionários python. Por exemplo, você pode editar o namespace global chamando globals (), que permite modificar o dicionário diretamente para vincular objetos e nomes: por exemplo globals () [name] = "object". Ótima resposta caso contrário.
Evan Rosica
4

Há um excelente artigo sobre namespaces do Python aqui . Para citar a parte relevante para responder sua pergunta sobre a referência entre escopos e espaços para nome:

Um escopo refere-se a uma região de um programa a partir da qual um espaço para nome pode ser acessado sem um prefixo.

Por exemplo, imagine um programa simples de laminação:

import random  # 'random' is in module namespace

def roll(sides=6):  # 'roll' is in module namespace, 'sides' is in roll's
    return random.randint(1, sides)  # both 'random' and 'sides' are in scope here

# but sides can't be accessed out here 

roll possui seu próprio espaço para nome , mas os nomes no espaço para nome do módulo também estão no escopo .

jonrsharpe
fonte
O @CarlSmith observa que a documentação antiga do Python diz a mesma coisa: "Um escopo é uma região textual de um programa Python onde um espaço de nome é diretamente acessível." Diretamente acessível '' aqui significa que uma referência não qualificada a um nome tenta encontrar o nome no espaço de nome ".
jonrsharpe 17/02
@CarlSmith, além do escopo adicional não local / anexo, isso mudou muito? Acho que estamos dizendo a mesma coisa - um espaço para nome contém os nomes e valores, e o escopo informa quais espaços para nome são acessíveis.
jonrsharpe
Eu apaguei meus comentários antigos.
Carl Smith