7
votes

Confusion sur la portée variable Python

Je suis tombé sur un seul code qui me perplexe. Voici un exemple minimal qui montre ceci:

def some_func():
   global some_var
   v = some_var["key1"]


0 commentaires

6 Réponses :


6
votes

Non, vous ne pouvez tout simplement pas réaffecter quelque_var code> dans une portée locale. Considérez les éléments suivants:

some_var = {}
def some_func():
    # some_var[5] = 6
    some_var = {1:2}
    some_var[3] = 4
some_func()
print (repr(some_var)) # {}


8 commentaires

C'est l'une des (très) peu de choses que je n'aime pas sur Python.


Ouais, mais le code lit uniquement des données de la dict. Pourquoi est-il possible sans l'utilisation de global ?


@Geo: Parce que l'attribution et l'accès sont des choses différentes.


@Geo c'est parce que vous pouvez accéder à une valeur d'une portée extérieure. C'est à quel point le scopage de Python fonctionne et si ce n'était pas comme ça, vous auriez à Global chaque variable et fonction VOULEVERTEZ UTILISER À VOTRE FONCTION .


@Geo: Vous pouvez faire référence à des variables dans une plus grande portée que votre actuelle. Vous ne pouvez pas vous assigner à eux. Vous devez utiliser le mot-clé global dans ce cas.


@ALPHA: Cela peut sembler bizarre, mais puisque vous créez de nouveaux habitants plus souvent que vous n'écrivez les non-locaux, c'est en fait un bon choix. En supposant la présence de non local bien sûr (sinon la fermeture peut devenir très laid). Accordé, un avertissement serait bien. Mais là encore, la dynamique ne rend pas cela facile.


@Delnan: Je suppose que cela a du sens, mais je suis un peu déroutant inutilement. De plus, si vous avez deux variables avec le même nom dans différentes étendues, une contenant l'autre, vous voulez généralement qu'ils référennent le même.


Je viens de réaliser que la ligne de sortie commentée # quelque_var [5] = 6 ne fonctionne pas car la variable locale créée juste en dessous des ombres, le global de le < / i> début de la portée de la fonction, et non parce que sa mauvaise syntaxe en soi: vous pouvez accéder au nom global, et si cela concerne un objet mutable, vous pouvez le changer, vous ne pouvez tout simplement pas reculer Le nom var à la portée mondiale. Donc, si vous commenciez cela à la place, le commentaire de l'autre fonctionnerait. Je sais que c'est ce que dit la réponse, mais je l'ai mal compris en première lecture, juste un avertissement amical aux autres :)



1
votes

Cela dépend de l'utilisation de la variable dans la fonction Erreur de portée variable Python


0 commentaires

3
votes

Il vous suffit d'utiliser global si vous souhaitez affecter une nouvelle valeur à cette variable.

portée imbriquée a été introduite dans Python 2.1 (et Activé Par défaut dans Python 2.2 ) (emphase MINE):

Mettez simplement, quand un nom de variable donné est non attribué une valeur dans une fonction (par une affectation ou le def , classe , ou importer déclarations), les références à la variable seront recherchées dans l'espace de noms local de la portée enfermante . Une explication plus détaillée des règles et une dissection de la mise en œuvre peut être trouvée dans le Pepp .


2 commentaires

Ah, alors réaffecter uniquement la variable nécessite l'utilisation de global . Tout le reste est un jeu juste?


@Geo non, vous ne pouvez pas del variables. Fondamentalement, vous pouvez simplement les lire - mais cela couvre presque n'importe quoi dans Python, y compris l'accès au réseau, appelant une méthode, appelant une méthode sur un objet, etc.



3
votes

Il y a une différence entre l'utilisation (appelant ou utiliser dans une expression) un nom d'une portée extérieure et l'affectation (et il y a une différence entre l'attribution d'une variable nue et l'attribution d'un élément d'un objet pointé par une variable - < Code> xy = ... et x [...] = ... comptez comme des appels de méthode!).

Il vous suffit de déclarer qu'une variable provient d'une portée extérieure si vous vous en attribuez. Dans Python 2, vous ne pouvez faire que cela avec des variables globales (via global var ), dans Python 3, vous pouvez le faire pour des étendues abritées (par exemple, des fermetures) à l'aide de nonLocal var .

Utiliser une variable non localisée comme dans votre exemple n'exige pas global . Cependant, il fait dès que vous attribuez la variable (avec la définition susmentionnée de l'affectation) n'importe où dans ce cadre - Ajoutez donc une ligne quelque_var = ... après la ligne où vous l'utilisez. Et vous obtiendrez un Unboundlocalerror . Reportez-vous à la documentation des détails Nitty Gritty.


0 commentaires

2
votes

Il vous suffit d'utiliser global si vous souhaitez attribuer à la variable, pour la lecture de la variable, cela n'est pas nécessaire . Cette différence n'est pas arbitraire, même si cela peut sembler comme ça d'abord.

Lors de la lecture d'une valeur, l'interprète peut simplement rechercher une variable locale nommée quelque_var , s'il ne peut pas le trouver, il recherche une variable globale de ce nom. Ce sont des sémantiques simples et simples en avant.

Lors de l'attribution de valeurs à une variable, l'interprète doit savoir si vous avez l'intention d'attribuer à une variable locale quelque_var ou une variable globale. L'interprète suppose que certains_var = 2 Lorsque l'appelé dans une fonction est attribué à une variable locale, cela a du sens, car c'est le cas le plus courant . Pour les temps relativement rares Lorsque vous souhaitez attribuer une variable globale à partir d'une fonction, vous utilisez le modificateur global global quelque_var = 2 .


0 commentaires

1
votes

L'attribution d'une valeur à un nom rend le nom local, à moins que le nom ne soit explicitement déclaré global.

b = 5

def foo():
   print b
   b = 7

foo()
>>> ???


0 commentaires