Comportement import python 3.7.2/ python 3.11.3

Résolu
Phil_1857 Messages postés 1872 Date d'inscription   Statut Membre Dernière intervention   -  
mamiemando Messages postés 33766 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

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
Diablo76 Messages postés 235 Date d'inscription   Statut Membre Dernière intervention   75
 

Salut Phil,

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

0
Phil_1857 Messages postés 1872 Date d'inscription   Statut Membre Dernière intervention   168
 

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
Diablo76 Messages postés 235 Date d'inscription   Statut Membre Dernière intervention   75
 

Ha bah non.

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

2
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

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

Posez votre question
Phil_1857 Messages postés 1872 Date d'inscription   Statut Membre Dernière intervention   168
 

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
Phil_1857 Messages postés 1872 Date d'inscription   Statut Membre Dernière intervention   168
 

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
Diablo76 Messages postés 235 Date d'inscription   Statut Membre Dernière intervention   75
 

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
yg_be Messages postés 23541 Date d'inscription   Statut Contributeur Dernière intervention   1 584
 

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

0
mamiemando Messages postés 33766 Date d'inscription   Statut Modérateur Dernière intervention   7 878 > yg_be Messages postés 23541 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
Phil_1857 Messages postés 1872 Date d'inscription   Statut Membre Dernière intervention   168
 

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

0
Diablo76 Messages postés 235 Date d'inscription   Statut Membre Dernière intervention   75
 

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

0