Comportement import python 3.7.2/ python 3.11.3

Résolu
Phil_1857 Messages postés 1883 Date d'inscription   Statut Membre Dernière intervention   -  
mamiemando Messages postés 33228 Date d'inscription   Statut Modérateur Dernière intervention   -

Bonjour,

J'ai un programme principal test.py:

import sys
import os

sys.path.append(os.getcwd() + r'\data')
from test_lib import *

et une bibliothèque de fonctions test_lib.py :

def get_os():

    if sys.platform in ('win32','linux'):
        font_default = ('Segoe UI', 9)
        key_codes = [13, 13]
        return font_default,0,0,0,0, key_codes
    else:
        font_default = ('Segoe UI', 10)
        key_codes = [1275068419, 603979789]
        return font_default,25,-0,15,-2, key_codes

Ceci fonctionne parfaitement en version 3.7.2 car sys utilisé dans get_os()

est importé dans test.py, et après vient l'import de test_lib

Par contre, en version 3.11.3, j'ai une erreur:

NameError: name 'sys' is not defined  à la ligne if sys.platform....

J'ai résolu ceci en ajoutant import sys dans test_lib.py

Quelque chose aurait-il changé entre les 2 versions ?

Merci d'avance pour vos réponses


Windows / Edge 121.0.0.0

7 réponses

  1. boubou
     

    Salut.

    Je me doutais que ce qui diffère est :

    https://docs.python.org/3/tutorial/modules.html#tut-pkg-import-star

    Je n'ai pas la 3.11 mais comme plus récent la 3.9 et en regardant le code source du module datetime des deux versions, en 3.9 il y a :

    __all__ = ("date", "datetime", "time", "timedelta", "timezone", "tzinfo",
               "MINYEAR", "MAXYEAR")

    Le import * c'est le mal ! les seules fois où je m'en sers est pour l'import de constantes, et encore tout dépend du nombre de constantes...

    1
  2. Diablo76 Messages postés 344 Date d'inscription   Statut Membre Dernière intervention   140
     

    Salut Phil,

    Je suis étonné qu'avec Python 3.7 ça pouvait fonctionner sans importer sys...

    0
  3. Phil_1857 Messages postés 1883 Date d'inscription   Statut Membre Dernière intervention   169
     

    Holà Diablo,

    Ben si : on importe sys dans test.py puis on importe test_lib plus bas

    Normalement, importer test_lib, ou écrire à la place le code contenu dedans

    c'est la même chose, c'est comme si on écrivait cà:

    import sys
    import os
    
    sys.path.append(os.getcwd() + r'\data')
    #from test_lib import *
    
    def get_os():
    
        if sys.platform in ('win32','linux'):
            font_default = ('Segoe UI', 9)
            key_codes = [13, 13]
            return font_default,0,0,0,0, key_codes
        else:
            font_default = ('Segoe UI', 10)
            key_codes = [1275068419, 603979789]
            return font_default,25,-0,15,-2, key_codes

    non ?

    0
    1. Diablo76 Messages postés 344 Date d'inscription   Statut Membre Dernière intervention   140
       

      Ha bah non.

      Tu dois importer sys (ou autre) dans chaque module qui l'utilise. 

      2
  4. boubou
     

    Salut,

    Diablo76 a raison.

    Les modules sont des espaces de noms, le module importé n'a pas connaissance de ce qu'il se passe dans celui qui l'importe.

    Chez moi, en 3.7 c'est bien une erreur disant NameError: name 'sys' is not defined, cela a toujours été le cas, même en python 2 dont l'erreur est NameError: global name 'sys' is not defined.

    0
  5. Vous n’avez pas trouvé la réponse que vous recherchez ?

    Posez votre question
  6. Phil_1857 Messages postés 1883 Date d'inscription   Statut Membre Dernière intervention   169
     

    Bizarre, chez moi, ça marche ...

    J'ai même plusieurs programmes qui marchent comme ça:

    cad3_common.py:

    import os
    import sys
    from copy import *
    import pickle
    import re

    cad3_modeller.py:

    from cad_3_common import *
    
    def get_file_objects(filename):
    	''' Opens the solid file and records the objects '''
    
        with open(filename,'rb') as fo:
            G.objects_list = pickle.load(fo)
            G.points_model = pickle.load(fo)
            G.faces = pickle.load(fo)
            G.edges = pickle.load(fo)

    cad3_modeller utilise pickle qui est importé dans cad3_common

    cad3_common est importé dans cad3_modeller

    0
  7. Phil_1857 Messages postés 1883 Date d'inscription   Statut Membre Dernière intervention   169
     

    Eureka !

    dans test_lib.py, il y a aussi 

    from datetime import *

    et je pense que sys est inclus dedans, je viens de faire un test, et c'est bien ça:

    # -*- coding:Utf-8 -*-
    
    from datetime import *
    
    def get_os():
    
        if sys.platform in ('win32','linux'):
            font_default = ('Segoe UI', 9)
            key_codes = [13, 13]
            return font_default,0,0,0,0, key_codes
        else:
            font_default = ('Segoe UI', 10)
            key_codes = [1275068419, 603979789]
            return font_default,25,-0,15,-2, key_codes

    Il y avait plusieurs imports, et je les ai éliminés un par un pour tester

    Et donc je pense qu'en 3.11.3, ils ont resserré les boulons 

    0
    1. Diablo76 Messages postés 344 Date d'inscription   Statut Membre Dernière intervention   140
       

      Ok, on comprend mieux, la logique est que chaque module importe ses propres dépendances, car la chose que l'on a besoin de connaitre de datetime, ce sont ses méthodes et attributs.

      Si demain datetime n'utilise plus sys.platform pour détecter l'os, ça posera un problème.

      Je ne sais pas si je suis clair dans ma réponse.

      0
    2. yg_be Messages postés 23437 Date d'inscription   Statut Contributeur Dernière intervention   1 588
       

      Ce qui confirme qu'il est préférable d'éviter "import *".

      0
      1. mamiemando Messages postés 33228 Date d'inscription   Statut Modérateur Dernière intervention   7 940 > yg_be Messages postés 23437 Date d'inscription   Statut Contributeur Dernière intervention  
         

        Pour préciser cette réponse, écrire un import du style

        from foo import *

        présente deux inconvénients qu'il faut bien distinguer.

        1) On ne sait pas ce qui est importé depuis le module foo, ce qui nuit à la lisibilité du code. On importe d'ailleurs probablement par la même occasion beaucoup de symboles qui n'ont aucune raison de l'être, voire qui peuvent entrer en collision avec d'autres symboles définis plus loin dans le code.

        2) En particulier, on importe non seulement les symboles définis dans foo, mais aussi tout symboles définis dans foo, ce qui inclue tous les symboles importés dans foo (qui eux, proviennent modules). Ainsi, si foo.py contient :

        from bar import Bar
        
        class Foo(Bar):
            pass

        ... alors :

        from foo import *

        ... importe non seulement Foo, mais aussi Bar.

        C'est là que les ennuis commencent, car on peut croire à tort que foo fournit Bar,  qui est en réalité fourni par le module bar. Là où ça devient problématique, c'est si l'implémentation de foo évolue. En effet, rien ne garantit que foo continuera de dépendre de bar, et donc rien ne garantit qu'il pourra continuer d'exposer par la suite Bar

        Ainsi si un module a besoin de Foo et Bar, il ne faut ni écrire :

        from foo import *

        ... ni (même si c'est mieux) :

        from foo import Foo, Bar

        ... mais :

        from foo import Foo
        from bar import Bar

        Bonne chance

        0
  8. Phil_1857 Messages postés 1883 Date d'inscription   Statut Membre Dernière intervention   169
     

    En tout cas, ce qui est sûr, c'est qu'en 3.7.2, ça marche comme ça ...

    0
    1. Diablo76 Messages postés 344 Date d'inscription   Statut Membre Dernière intervention   140
       

      Oui et je me souviens que l'on avait eu ce même genre de discutions avec Tkinter et le module RegEx (re).

      0