Quelle est la relation entre la portée et les espaces de noms en Python?

12

Dans de nombreuses ressources, j'ai trouvé que «portée» et «espaces de noms» sont utilisés de manière interchangeable, ce qui semble un peu déroutant car ils signifient des choses différentes.

  • La portée définit la région du code où un nom est disponible.
  • La règle LEGB définit la façon dont les noms sont recherchés.
  • L'espace de noms est un endroit où vous recherchez des noms.

Alors j'ai lu:

  • "les noms sont liés à un espace de noms en fonction de l'endroit où ils sont attribués ..." (ce qui, je crois, concerne les portées dans la portée lexicale).
  • "les fonctions ajoutent une couche d'espace de noms supplémentaire à vos programmes" [ réf. ] (n'ajoutent-ils pas une portée locale supplémentaire?)
  • "tous les noms attribués à l'intérieur d'une définition de fonction sont placés dans la portée locale (l'espace de nom associé à l'appel de fonction)."
  • "portée globale - c'est-à-dire un espace de noms dans lequel vivent des variables créées (attribuées) au niveau supérieur du fichier de module."

* toutes les citations proviennent de l'apprentissage de python 5e édition ch17

Les espaces de noms en Python sont-ils la manière dont les étendues sont implémentées? S'agit-il de la même chose? Quelqu'un peut-il m'éclairer?

Nikos
la source
1
Pourriez-vous fournir des références pour les citations - je pourrais en trouver une, mais pas l'autre.
jonrsharpe
1
Les espaces de noms ne sont qu'un type de portée. Voir stackoverflow.com/questions/291978/…
Robert Harvey

Réponses:

16

Un espace de noms est un dictionnaire, mappant des noms (sous forme de chaînes) à des valeurs. Lorsque vous effectuez une affectation, par exemple a = 1, vous mutez un espace de noms. Lorsque vous faites une référence, par exemple print(a), Python parcourt une liste d'espaces de noms pour essayer d'en trouver un avec le nom comme clé.

Une portée définit quels espaces de noms seront examinés et dans quel ordre. La portée de toute référence commence toujours dans l'espace de noms local et se déplace vers l'extérieur jusqu'à ce qu'elle atteigne l'espace de noms global du module, avant de passer à builtins(l'espace de noms qui fait référence aux fonctions et constantes prédéfinies de Python, comme rangeet getattr), qui est la fin de la ligne .

Imaginez que vous ayez une fonction nommée inner, imbriquée dans une fonction globale nommée outeret innercontenant une référence à un nom. Python regarde d'abord dans l' innerespace de noms. Si le nom n'est pas là, Python regarde alors dans l' outerespace de noms. Si cela échoue, Python essaie l' globalespace de noms du module , puis l' builtinespace de noms, en lançant éventuellement un NameErrorsi le nom n'est pas trouvé.

Lorsque nous disons qu'il se xtrouve dans l'espace de noms d'une fonction, nous voulons dire qu'il y est défini localement dans la fonction. Lorsque nous disons qu'il xest dans la portée de la fonction, nous voulons dire que xc'est soit dans l'espace de noms de la fonction, soit dans l'un des espaces de noms externes dans lequel l'espace de noms de la fonction est imbriqué.

Chaque fois que vous définissez une fonction, vous créez un nouvel espace de noms et une nouvelle étendue. L'espace de noms est le nouveau hachage local des noms. La portée est la chaîne implicite d'espaces de noms qui commence au nouvel espace de noms, puis se fraye un chemin à travers tous les espaces de noms externes (étendues externes), jusqu'à l'espace de noms global (la portée globale) et jusqu'aux éléments intégrés.

Les termes peuvent être utilisés presque de façon interchangeable, mais ce n'est pas parce qu'ils signifient la même chose; c'est parce qu'ils se chevauchent beaucoup dans ce qu'ils impliquent.

Carl Smith
la source
3
"Les termes peuvent être utilisés presque de manière interchangeable, mais ce n'est pas parce qu'ils signifient la même chose; c'est parce qu'ils se chevauchent beaucoup dans ce qu'ils impliquent."
Nikos
2
Cette réponse est correcte dans son esprit, mais erronée dans les détails. Les classes en Python n'introduisent pas de nouvel espace de noms, c'est pourquoi les attributs de classe doivent être qualifiés avec le nom de classe et pourquoi les attributs d'instance doivent être qualifiés avec le nom d'instance. Les niveaux d'espace de noms en Python de l'intérieur vers l'extérieur sont Local, Enclosing, Global et Built-in. Une classe peut être définie à n'importe lequel de ces niveaux, mais les membres d'une classe doivent toujours être qualifiés.
Rob Smallshire
Vous avez raison. Les cours ne fonctionnent pas comme je l'ai dit. Je pensais qu'ils créent une portée lexicale comme une fonction, mais ce n'est pas le cas. Veuillez mettre à jour la réponse si vous avez le temps, sinon je le ferai à un moment donné. Merci.
Carl Smith
1
+1 Réponse brillante, encapsulant une telle subtilité si économiquement. J'ai trouvé cela très utile, merci!
seeker
1
"Un espace de noms est un hachage de noms, de paires de valeurs, un peu comme un dictionnaire Python" - je suis presque sûr que les espaces de noms sont stockés en tant que dictionnaires python. Par exemple, vous pouvez modifier l'espace de noms global en appelant globals (), ce qui vous permet de modifier directement le dictionnaire pour lier des objets et des noms: par exemple globals () [name] = "object". Excellente réponse sinon.
Evan Rosica
4

Il y a un excellent article sur les espaces de noms Python ici . Pour citer la partie pertinente pour répondre à votre question sur la référence entre les étendues et les espaces de noms:

Une portée fait référence à une région d'un programme à partir de laquelle un espace de noms est accessible sans préfixe.

Par exemple, imaginez un simple programme de lancer de matrice:

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 a son propre espace de noms , mais les noms dans l'espace de noms du module sont également dans la portée .

jonrsharpe
la source
@CarlSmith note que la première documentation Python dit la même chose: "Une étendue est une région textuelle d'un programme Python où un espace de nom est directement accessible." Directement accessible '' signifie ici qu'une référence non qualifiée à un nom tente de trouver le nom dans l'espace de noms. "
jonrsharpe
@CarlSmith en dehors de la portée supplémentaire non locale / englobante, cela a-t-il beaucoup changé? Je pense que nous disons la même chose - un espace de noms contient les noms et les valeurs, et la portée vous indique quels espaces de noms sont accessibles.
jonrsharpe
J'ai supprimé mes anciens commentaires.
Carl Smith