bon, voici l'affaire. Python est un peu bizarre, en ce qu'elle maintient le tout dans un dictionnaire pour les différents domaines. L'original a,b,c sont dans la partie supérieure de la portée et donc, dans ce supérieure dictionnaire. La fonction dispose de son propre dictionnaire. Lorsque vous atteignez l' print(a)
et print(b)
des déclarations, il n'y a rien de ce nom dans le dictionnaire, donc Python regarde la liste et les trouve dans les clobal dictionnaire.
Nous en arrivons maintenant à l' c+=1
, ce qui est, bien sûr, équivalent à c=c+1
. Quand Python scans de cette ligne, il est dit "ahah, il y a une variable nommée c, je vais le mettre dans mon domaine local dictionnaire." Puis quand il va à la recherche pour une valeur de c pour le c sur le côté droit de la cession, il trouve sa variable locale nommée c, qui n'a pas encore de valeur, et donc génère l'erreur.
L'énoncé global c
mentionné ci-dessus indique simplement à l'analyseur qu'il utilise le c de la portée mondiale et donc n'a pas besoin d'un nouveau.
La raison pour laquelle il dit qu'il y a un problème sur la ligne, il n'est parce qu'il est effectivement à la recherche pour les noms avant d'essayer de générer le code, et donc dans un certain sens, ne pensez pas qu'il est vraiment en train de faire cette ligne encore. Je dirais que c'est une fonctionnalité d'un bug, mais c'est généralement une bonne pratique pour juste apprendre à ne pas prendre un compilateur de messages trop au sérieux.
Si c'est tout le confort, j'ai probablement passé une journée à creuser et à expérimenter avec cette même question avant que je trouve quelque chose de Guido a écrit sur les dictionnaires qui m'a Tout Expliqué.
Mise à jour, voir les commentaires:
Il n'a pas de scanner le code à deux reprises, mais il n'scanner le code en deux phases, lexing et de l'analyse.
Examiner comment l'analyse de cette cline de code fonctionne. L'analyseur lexical lit le texte source et la décompose en lexèmes, le "petit composantes de la grammaire. Alors, quand il frappe la ligne
c+=1
il rompt en quelque chose comme
SYMBOL(c) OPERATOR(+=) DIGIT(1)
L'analyseur voudrait faire cela dans un arbre d'analyse et de l'exécuter, mais puisque c'est une affectation, avant qu'il ne, il semble pour le nom de c dans le local de dictionnaire, de ne pas le voir, et l'insère dans le dictionnaire, le marquer comme non initialisée. Dans un complètement langage compilé, il suffit d'aller dans la table de symboles et d'attente pour les analyser, mais depuis, il n'aura PAS le luxe d'un second passage, le lexer fait un peu de travail supplémentaire pour rendre la vie plus facile plus tard. Seulement, alors qu'il voit l'OPÉRATEUR, voit que les règles de dire "si vous avez un opérateur += la gauche doit avoir été initialisé" et dit "oups!"
Le point ici est qu'il n'a pas vraiment commencé l'analyse de la ligne de encore. Ce est tout se passe sorte de, préparatoires à la réelle analyser, de sorte que la ligne de compteur n'a pas progressé à la ligne suivante. Ainsi, lorsqu'il signale l'erreur, il pense toujours ses sur la ligne précédente.
Comme je l'ai dit, on pourrait soutenir que c'est de la convivialité d'un bug, mais sa en fait assez commun. Certains compilateurs sont plus honnêtes à ce sujet et de dire "erreur sur ou autour de la ligne XXX", mais celui-ci ne fonctionne pas.