IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Python Discussion :

Portée des variables [Python 2.X]


Sujet :

Python

  1. #1
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 699
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 699
    Points : 30 999
    Points
    30 999
    Billets dans le blog
    1
    Par défaut Portée des variables
    Bonjour

    J'ai une petite interrogation sur la portée d'une variable. Tantôt je la vois, tantôt je ne la vois plus.

    Petit exemple

    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    def fct():
    	print(toto)
     
    toto=10
    fct()
    print(toto)
    Jusqu'ici tout fonctionne comme indiqué sur le tuto de ce forum. Ma variable toto est globale et non modifiable mais visible dans la fonction donc ma fonction la voit et peut l'afficher.

    Rajoutons maintenant 1 ligne
    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    def fct():
    	toto=5
    	print(toto)
     
    toto=10
    fct()
    print(toto)
    Je redéfinis une variable locale dont la visibilité surclasse la globale. Dans la fonction elle vaut 5 mais la globale inchangée reste à 10. Ca va encore.

    Rajoutons maintenant une dernière ligne
    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    def fct():
    	print(toto)
    	toto=5
    	print(toto)
     
    toto=10
    fct()
    print(toto)
    Et là, rien ne va plus. Python me dit qu'il ne connait pas la variable "toto" et lève une exception au premier print. Pourtant à cet endroit il devrait voir la globale qui n'a pas encore été supplantée par la locale !!! (à ce moment là, il n'y a encore aucune différence avec le premier code)...
    On dirait que puisque "toto" a été définie dans la fonction, elle n'a alors plus le droit d'être invoquée avant sa définition et ce, même si une globale existe à son nom. Et cela impliquerait alors que Python fait au-moins 2 évaluations d'un code lors de son exécution...

    Merci à ceux qui pourront m'éclairer de leurs avis à ce sujet...
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  2. #2
    Nouveau membre du Club
    Homme Profil pro
    Technicien maintenance
    Inscrit en
    Août 2015
    Messages
    43
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Eure (Haute Normandie)

    Informations professionnelles :
    Activité : Technicien maintenance
    Secteur : Industrie

    Informations forums :
    Inscription : Août 2015
    Messages : 43
    Points : 30
    Points
    30
    Par défaut
    Bonjour,

    il n'y a aucune variable globale dans le code
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    def fct():
    	print(toto)
    	toto=5
    	print(toto)
    Le premier print(toto) renvoi la valeur de toto extérieure à la fonction.
    le toto=5 affecte la valeur 5 à une deuxième variable toto locale à la fonction (car toto extérieur en lecture seule), et le deuxième print(toto) affiche la vauleur local de la fonctionne définie juste avant.
    Il faudrait déclarer toto comme globale au sein de la fonction pour qu'elle le soit.
    Enfin je crois arretez moi si je délire (vu votre nombre de messages c'est moi qui déraille)

  3. #3
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 287
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 287
    Points : 36 776
    Points
    36 776
    Par défaut
    Salut,

    Citation Envoyé par Sve@r Voir le message
    Merci à ceux qui pourront m'éclairer de leurs avis à ce sujet...
    C'est dans la FAQ Python qui traduit par un exemple simple ce qui est écrit dans le chapitre résolution des noms dans un langage un peu technique.

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  4. #4
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 699
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 699
    Points : 30 999
    Points
    30 999
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par esope60 Voir le message
    il n'y a aucune variable globale dans le code
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    def fct():
    	print(toto)
    	toto=5
    	print(toto)
    Moui, si tu n'en mets que la moitié alors effectivement, il n'y en a pas. Mais selon ta logique il n'y en n'a pas non plus dans mon tout premier code...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    def fct():
    	print(toto)
    Maintenant tu peux rajouter toto=10 au dessus de la fonction que cela ne change rien...

    Citation Envoyé par esope60 Voir le message
    Le premier print(toto) renvoi la valeur de toto extérieure à la fonction.
    le toto=5 affecte la valeur 5 à une deuxième variable toto locale à la fonction (car toto extérieur en lecture seule), et le deuxième print(toto) affiche la vauleur local de la fonctionne définie juste avant.
    C'était effectivement comme ça que je le voyais. Mais visiblement cela n'est pas le cas...

    Citation Envoyé par esope60 Voir le message
    Enfin je crois arretez moi si je délire (vu votre nombre de messages c'est moi qui déraille)
    Ca ne veut pas dire grand chose. Je suis très actif sur le forum C et aussi shell mais ce n'est pas parce que je réponds souvent là bas que je connais tout sur tout (ou même tout sur Python).
    Et puis même la mer n'est formée que de gouttes d'eau
    Merci de ton intervention

    Citation Envoyé par wiztricks Voir le message
    C'est dans la FAQ Python qui traduit par un exemple simple ce qui est écrit dans le chapitre résolution des noms dans un langage un peu technique.
    Merci de ton aide. Effectivement c'est écrit
    A scope defines the visibility of a name within a block. If a local variable is defined in a block, its scope includes that block. If the definition occurs in a function block, the scope extends to any blocks contained within the defining one, unless a contained block introduces a different binding for the name.
    J'ai bien compris le truc. Je m'interroge toutefois toujours sur la façon dont Python analyse. En effet, il est écrit que si la définition arrive dans une fonction, le scope s'étend à toute la fonction. Mais pour étendre le scope à tout le bloc de la fonction (donc y compris les lignes situées au dessus), il faut bien faire au-moins 2 passes non ?

    Encore merci
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  5. #5
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 287
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 287
    Points : 36 776
    Points
    36 776
    Par défaut
    Salut,

    Citation Envoyé par Sve@r Voir le message
    Mais pour étendre le scope à tout le bloc de la fonction (donc y compris les lignes situées au dessus), il faut bien faire au-moins 2 passes non ?
    Il faut aller voir les sources de l'implémentation Python.
    Pour faire vite on peut observer les différences dans bytecode généré pour ces constructions.
    Ici dis.dis(f) traduira l'accès à toto par LOAD_GLOBAL 1 (toto).
    Si toto n'a pas été créé dans le scope global çà va planter en NameError.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    def f():
          print(toto)
          toto = 1
    alors qu'ici ce sera LOAD_FAST 0 (toto).
    Techniquement, si on "compile" une fonction, il va bien falloir construire une table de symboles, histoire de savoir si on va générer un LOAD_GLOBAL ou un LOAD_FAST.
    Dans le deuxième cas, çà va marquer "toto" comme variable locale (à cause de l'assignation).
    Puis lorsqu'on exécute le LOAD_FAST 0 (toto), on plante en UnboundLocalError: rien n'ayant été encore assigné à la variable (locale).
    note: çà se fait en 2 étapes mais côté compilation, pas besoin de faire çà en 2 passes.

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  6. #6
    Membre confirmé
    Homme Profil pro
    Développeur banc de test
    Inscrit en
    Mai 2014
    Messages
    199
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur banc de test
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Mai 2014
    Messages : 199
    Points : 482
    Points
    482
    Par défaut
    Bonjour,

    D'où l'importance d'éviter d'écrire un code dans le __main__, il vaut mieux créer une fonction "main" ça évitera bien des problèmes d'appels implicites de variables globales.

    Et si vous voulez vraiment utiliser des variables globales, alors faites-le explicitement pour éviter que l'interpréteur choisisse si c'est local ou global : https://docs.python.org/3/reference/...obal-statement

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    def fct():
        global toto # Déclare explicitement toto comme global
        print(toto)
        toto=5
        print(toto)
     
    toto=10
    fct()
    print(toto)
    La syntaxe global permet de déclarer une variable en global même si elle n'existe pas encore en globale.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    def fct():
        global toto, titi
        print(toto)
        toto=5
        print(toto)
        titi = 2
     
    toto=10
    fct()
    print(toto)
    print(titi)

    La suite pour Python 3 uniquement

    Et tant qu'à être dans la résolution de portée, autre cas peu usuel :
    La création d'une fonction dans une autre fonction permet de créer des variables locales propre à cette sous-fonction, et pour atteindre les variables locales de la fonction au dessus, il faut utiliser la syntaxe nonlocal.

    pour ceux que ça intéresse je m'étais fait un script qui référence tous les cas de figure :

    local nonlocal global scopes.py:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    # -*- coding: utf-8 -*-
    # Python 3
     
    x = "a" # (1) global scope
    y = "y"
     
    def main(): # {
        x = 0 # (2) local/main scope
     
        def change_local_x(): # { local/main scope
            value = 1
            x = value # (3) initialization = implicit local
            print("change_local_x() {!r}".format(x))
        # }
     
        def change_nonlocal_x(): # { local/main scope
            nonlocal x # (2)
            value = 1
            x = value
            print("change_nonlocal_x() {!r}".format(x))
        # }
     
        def change_global_x(): # { local/main scope
            global x # (1) explicit global
            value = "b"
            x = value
            print("change_global_x() {!r}".format(x))
        # }
     
        def print_nonlocal_or_global_x_y(): # { local/main scope
            print("print_nonlocal_or_global_x_y(): {!r}, {!r}".format(x, y)) # implicit (2) nonlocal if exists or (1) global
        # }
     
        def print_global_x(): # { local/main scope
            global x # explicit global
            print("print_global_x(): {!r}".format(x))
        # }
     
        print("local x: {!r}".format(x))
        print()
     
        print_global_x()
        print_nonlocal_or_global_x_y()
        print()
     
        change_local_x()
        print("local x: {!r}".format(x))
        print()
     
        change_nonlocal_x()
        print("local x: {!r}".format(x))
        print()
     
        change_global_x()
        print("local x: {!r}".format(x))
    # } main
     
    print("global x: {!r}".format(x))
    print("global y: {!r}".format(y))
    main()
    print("global x: {!r}".format(x))
     
    # global x: 'a'
    # global y: 'y'
    # local x: 0
    #
    # print_global_x(): 'a'
    # print_nonlocal_or_global_x_y(): 0, 'y'
    #
    # change_local_x() 1
    # local x: 0
    #
    # change_nonlocal_x() 1
    # local x: 1
    #
    # change_global_x() 'b'
    # local x: 1
    # global x: 'b'

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 8
    Dernier message: 17/02/2005, 09h05
  2. [FLASH MX] Portée des variables ???
    Par mic79 dans le forum Flash
    Réponses: 2
    Dernier message: 08/02/2005, 10h21
  3. Portée des variables vbscript vers ASP
    Par Immobilis dans le forum ASP
    Réponses: 3
    Dernier message: 03/11/2004, 10h14
  4. [XSL]Problème de portée des variables
    Par djulesp dans le forum XSL/XSLT/XPATH
    Réponses: 6
    Dernier message: 17/09/2004, 10h34
  5. [Portée] portée des variables
    Par parksto dans le forum Langage
    Réponses: 7
    Dernier message: 09/05/2004, 21h05

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo