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 :

[IDLE] [espace de noms] [variable globale] [fonction] [Python 3.X]


Sujet :

Python

  1. #1
    Nouveau membre du Club
    Homme Profil pro
    -
    Inscrit en
    Septembre 2011
    Messages
    25
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : -
    Secteur : Industrie

    Informations forums :
    Inscription : Septembre 2011
    Messages : 25
    Points : 30
    Points
    30
    Par défaut [IDLE] [espace de noms] [variable globale] [fonction]
    Bonjour à tout le monde,

    J’ai un soucis avec un résultat inattendu lorsque j’exécute une fonction dans l’interpréteur.
    Je dois passer à côté de quelque chose, je pense que c’est lié aux espaces de noms mais je ne comprends pas…

    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
     
    # -*- coding:Utf-8 -*-
     
    a=9999
     
    def monter():
        global a
        a=a+1
        print("a")
        print(a)
        print(id(a))
     
    def setA():
        global a
        a=10
        print("a")
        print(a)
        print(id(a))
     
    if __name__ == "__main__":
        print(globals())
        print("a")
        print(a)
        print(id(a))
        print("-------")
        print("setA")
        setA()
        print("-------")
        print("a")
        print(a)
        print(id(a))
        print("-------")
        print("monter")
        monter()
        print("-------")
        print("a")
        print(a)
        print(id(a))
        print("-------")
    En exécutant le code (main), j’obtiens le résultat suivant (qui est correct):
    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
     
    {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x000001CF9F772640>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'test.py', '__cached__': None, 'a': 9999, 'monter': <function monter at 0x000001CF9FCC7CA0>, 'setA': <function setA at 0x000001CF9FCC7E50>}
    a
    9999
    1991250639312
    -------
    setA
    a
    10
    140704708233152
    -------
    a
    10
    140704708233152
    -------
    monter
    a
    11
    140704708233184
    -------
    a
    11
    140704708233184
    -------
    La variable globale est bien modifiée.

    Maintenant dans l’interpréteur:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    Python 3.8.6rc1 (tags/v3.8.6rc1:08bd63d, Sep  7 2020, 23:10:23) [MSC v.1927 64 bit (AMD64)] on win32
    Type "help", "copyright", "credits" or "license" for more information.
    >>> from test import setA, monter, a
    >>> print(globals())
    {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, 'setA': <function setA at 0x0000018AC4F07EE0>, 'monter': <function monter at 0x0000018AC4F07E50>, 'a': 9999}
    >>> print(a)
    9999
    >>> setA()
    a
    10
    140704708233152
    >>> print(a)
    9999
    La variable globale n’est pas modifiée. Pourquoi 999 et pas 10 ?

    Merci d’avance pour votre aide

  2. #2
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 690
    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 690
    Points : 30 984
    Points
    30 984
    Billets dans le blog
    1
    Par défaut
    Bonjour

    J'ai un peu modifé ton script.

    Voici ma version
    Code python : 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
    #!/usr/bin/env python3
    # coding: utf-8
     
    a=9999
     
    def monter():
    	global a
    	print("monter a")
    	a=a+1
    	print("a=", a, id(a))
     
    def setA():
    	global a
    	a=1000
    	print("set a")
    	print("a=", a, id(a))
     
    if __name__ == "__main__":
    	print(globals())
    	print("départ a=", a, id(a))
    	setA()
    	print("final a=", a, id(a))
    	monter()
    	print("final a=", a, id(a))

    Voilà, un peu moins de fioritures, plus a l'essentiel.

    Déjà pourquoi j'ai mis a=1000 au lieu de a=10? Parce que les valeurs de -5 jusqu'à 255 sont (je sais pas trop comment dire), en quelque sorte stockées en dur dans Python. Donc tu écris a=10; print(id(a)) tu auras toujours la même valeur ; tandis que tu écris a=1000; print(id(a)) tu auras à chaque fois des valeurs différentes prouvant que la variable est stockée à différentes positions en mémoire donc si id(a) donne la même valeur à différents points du code c'est preuve qu'on tape bien dans la même variable (et non dans le même nombre magique stocké dans Python).

    Accessoirement le fait que a=1000; print(id(a)) donne à chaque fois des valeurs différentes est lié à l'immutabilité de l'int. Chaque affectation crée alors un nouveau int placé ailleurs dans la mémoire puis supprime l'int précédent (Python ne s'embête pas à regarder si "a" existe déjà pour éventuellement le modifier ou le créer sinon).

    Donc au résultat
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x7fe368d90b50>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'x.py', '__cached__': None, 'a': 9999, 'monter': <function monter at 0x7fe368c70ca0>, 'setA': <function setA at 0x7fe368c70f70>}
    départ a= 9999 140614693083376
    set a
    a= 1000 140614694328272
    final a= 1000 140614694328272
    monter a
    a= 1001 140614692642672
    final a= 1001 140614692642672
    Chaque affectation a donc créé un nouveau "a", mais comme il était marqué global, le "a" de la fonction a écrasé le "a" initial.

    Maintenant, dans idle
    Code python : 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
    >> from x /* mon script se nomme "x.py" */ import setA, monter, a
    >>> print(a, id(a))
    9999 140526625484624
    >>> setA()
    set a
    a= 1000 140526625484592
    >>> print(a, id(a))
    9999 140526625484624
    >>> monter()
    monter a
    a= 1001 140526625910736
    >>> monter()
    monter a
    a= 1002 140526625910544
    >>> monter()
    monter a
    a= 1003 140526625910704
    >>> print(a, id(a))
    9999 140526625484624
    >>>
    Ce que l'on voie, c'est que les fonctions ont bien créé un "a" global pour leur espace de travail puisque les appels à monter() font bien monter le "a" mis à 1000 dans la fonction set(). Ainsi il passe à 1001, 1002, 1003, etc....
    Mais ce "a" de leur espace de travail n'est pas le "a" importé au départ. Probablement parce que l'espace de travail de idle est lui-aussi un espace "à part", ce qui est montré par son id() qui n'a pas changé entre le début et la fin (toujours à 140526625484624). Et comme 9999 n'est pas compris entre -5 et 256, on est bien certain que le "a" n'a réellement pas changé.

    Accessoirement, on n'est pas obligé d'importer "a", ça marche aussi si on le crée directement
    Code python : 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
    >>> a=9999
    >>> a, id(a)
    (9999, 140526625910544)
    >>> setA()
    set a
    a= 1000 140526625484592
    >>> monter()
    monter a
    a= 1001 140526625910736
    >>> monter()
    monter a
    a= 1002 140526625910704
    >>> monter()
    monter a
    a= 1003 140526625910736
    >>> a, id(a)
    (9999, 140526625910544)
    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]

  3. #3
    Nouveau membre du Club
    Homme Profil pro
    -
    Inscrit en
    Septembre 2011
    Messages
    25
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : -
    Secteur : Industrie

    Informations forums :
    Inscription : Septembre 2011
    Messages : 25
    Points : 30
    Points
    30
    Par défaut
    Merci beaucoup Sve@r pour ta réponse.

    Très intéressant le dernier test que tu as réalisé sans importer le "a".

    En quelques sorte, ça signifie qu’il n’est pas possible de modifier une variable globale dans l’environnement idle/shell python.

    C’est vraiment étonnant ce comportement.
    Je partage ton avis.
    Probablement parce que l'espace de travail de idle est lui-aussi un espace "à part"
    Je ne sais pas si je trouverai la réponse dans la doc concernant cet espace "à part".
    Je vais jeter un coup d’oeil, si je trouve quelque chose, j’ajouterai à la discussion.

    Encore merci

  4. #4
    Membre émérite

    Homme Profil pro
    Ingénieur calcul scientifique
    Inscrit en
    Mars 2013
    Messages
    1 229
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur calcul scientifique

    Informations forums :
    Inscription : Mars 2013
    Messages : 1 229
    Points : 2 328
    Points
    2 328
    Par défaut
    Sinon, comme je le dis à tous mes stagiaires chaque année : il faut bannir global, car il est très souvent employé à mauvais escient et est source de problème difficile à débugguer comme c'est le cas ici.

    Si une fonction a besoin de connaitre la valeur de qqch de l'extérieur, alors on met ce qqch en paramètre de la fonction plutot que de faire un global. Si on a besoin de l'extérieur de garder une ou plusieurs valeurs calculées par la fonction, alors on met ces valeurs dans un return
    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
    a=9999
     
    def monter(a):
    	print("monter a")
    	a=a+1
    	return a
     
    def setA():
    	a=1000
    	print("set a")
    	return a
     
    if __name__ == "__main__":
    	print(globals())
    	print("départ a=", a, id(a))
    	a=setA()
    	print("final a=", a, id(a))
    	a=monter(a)
    	print("final a=", a, id(a))
    Et si on a vraiment besoin plus spécifiquement de fonction qui vont fonctionner ensemble en partageant des variables communes c'est là que la POO prend du sens :


    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
    a=9999
     
    class A(): 
        def __init__(self):
    	self.a=1000
    	print("set a")
    	print("a=", self.a, id(self.a))
     
        def monter(self):
    	print("monter a")
    	self.a += 1
    	print("a=", self.a, id(self.a))
     
    if __name__ == "__main__":
    	print(globals())
    	print("départ a=", a, id(a))
    	mon_objet_contenant_a = A() ##Appel A.__init__
    	print("final a=", mon_objet_contenant_a.a, id(mon_objet_contenant_a.a))
    	mon_objet_contenant_a.monter()
    	print("final a=", mon_objet_contenant_a.a, id(mon_objet_contenant_a.a))

  5. #5
    Nouveau membre du Club
    Homme Profil pro
    -
    Inscrit en
    Septembre 2011
    Messages
    25
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : -
    Secteur : Industrie

    Informations forums :
    Inscription : Septembre 2011
    Messages : 25
    Points : 30
    Points
    30
    Par défaut
    Merci @lg_53

    Et si on a vraiment besoin plus spécifiquement de fonction qui vont fonctionner ensemble en partageant des variables communes c'est là que la POO prend du sens :
    Effectivement!

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

Discussions similaires

  1. [XL-2010] importer un fichier avec un nom variable en fonction de la date
    Par pepsister dans le forum Macros et VBA Excel
    Réponses: 1
    Dernier message: 16/06/2014, 12h10
  2. [XL-2003] Shell avec espaces et nom variable
    Par many6976 dans le forum Macros et VBA Excel
    Réponses: 5
    Dernier message: 04/07/2013, 14h19
  3. [XPATH] Mauvais espace de nom pour les fonctions XPath?
    Par avenger1 dans le forum XSL/XSLT/XPATH
    Réponses: 3
    Dernier message: 10/03/2008, 14h20
  4. [FLASH MX] nom variable pour une fonction
    Par totoche dans le forum Flash
    Réponses: 2
    Dernier message: 20/12/2005, 14h00
  5. Réponses: 10
    Dernier message: 06/04/2005, 15h44

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