Pourquoi «import *» est-il mauvais?


153

Il est recommandé de ne pas utiliser import *en Python.

Quelqu'un peut-il s'il vous plaît partager la raison de cela, afin que je puisse éviter de le faire la prochaine fois?



2
cela dépend si vous créez des scripts ou écrivez du code que vous devez réutiliser. il est parfois avantageux d'ignorer les normes de code. "import *" peut également convenir si vous avez une convention de dénomination qui indique clairement la provenance des éléments. par exemple "de l'importation de chats *; TabbyCat; MaineCoonCat; CalicoCat;"
gatoatigrado

3
import *ne fonctionne pas pour moi en premier lieu dans Python 2 ou 3.
joshreesjones

1
Est-ce que cela répond à votre question? Que signifie exactement "import *"?
AMC

Réponses:


223
  • Parce qu'il met beaucoup de choses dans votre espace de noms (peut masquer un autre objet de l'importation précédente et vous ne le saurez pas).

  • Parce que vous ne savez pas exactement ce qui est importé et que vous ne pouvez pas trouver facilement à partir de quel module une certaine chose a été importée (lisibilité).

  • Parce que vous ne pouvez pas utiliser des outils sympas comme la pyflakesdétection statique des erreurs dans votre code.


2
Ouais, je déteste vraiment mon travail quand quelqu'un utilise * import, parce que je ne peux pas simplement lancer pyflakes et être heureux, mais je dois réparer ces importations. C'est bien cependant, qu'avec ces pyflakes, ça m'aide à :-)
gruszczy

7
À titre d'exemple concret, de nombreux utilisateurs de NumPy ont été mordus par l' numpy.anyobservation anyquand ils le font from numpy import *ou un outil «utile» le fait pour eux.
user2357112 prend en charge Monica

1
Dois-je éviter d'utiliser le commutateur --pylab pour IPython pour les mêmes raisons?
timgeb

6
Pour mettre en évidence un risque auquel je n'avais jamais pensé avant de lire ceci ("pourrait masquer un autre objet de l'importation précédente"): import *rend l' ordre des importinstructions significatif ... même pour les modules de bibliothèque standard qui ne se soucient normalement pas de l'ordre d'importation . Quelque chose d'aussi innocent que de classer vos importdéclarations par ordre alphabétique pourrait briser votre script lorsqu'une ancienne victime de la guerre d'importation devient le seul survivant. (Même si votre script fonctionne maintenant et ne change jamais, il pourrait soudainement échouer un peu plus tard si le module importé introduit un nouveau nom qui remplace celui sur lequel vous vous
Kevin J. Chase

49

Selon le Zen de Python :

L'explicite vaut mieux que l'implicite.

... vous ne pouvez pas discuter avec ça, sûrement?


29
En fait, vous pouvez discuter avec cela. C'est aussi totalement incohérent, étant donné que vous ne déclarez pas les variables explicitement en Python, elles apparaissent juste une fois que vous leur assignez.
Konrad Rudolph

7
@gruszczy: déclarer des variables est redondant par rapport à quoi ? Attribution? Non, ce sont deux concepts distincts et déclarer quelque chose transmet une information très distincte et importante. Quoi qu'il en soit, l'explicitation est toujours un peu liée à la redondance, ce sont deux faces d'une même pièce.
Konrad Rudolph

3
@kriss bien, mais ce n'était pas mon propos. Mon point était que le fait de ne pas déclarer explicitement une variable entraîne des erreurs. Vous dites que "la cession sans [déclaration] est impossible". Mais c'est faux, tout ce que je veux dire, c'est que Python rend malheureusement exactement cela possible.
Konrad Rudolph

3
@kriss Une autre information donnée au compilateur par la déclaration est le fait que vous avez effectivement l'intention de déclarer une nouvelle variable. C'est une information cruciale pour le système de typage. Vous dites que les IDE modernes résolvent le problème des erreurs de frappe mais c'est tout simplement faux, et en fait c'est un problème substantiel dans les langages non compilés statiquement, c'est pourquoi Perl a ajouté use strict(JavaScript var). En passant , bien sûr, Python n'est pas sans type (il est en fait fortement typé). Quoi qu'il en soit, même si vous aviez raison, cela contredirait toujours le Zen de Python, cité dans cette réponse.
Konrad Rudolph

3
@kriss Vous vous trompez: réutiliser le même nom de variable n'est pas un problème - réutiliser la même variable est (c'est-à-dire le même nom dans la même portée). Des déclarations explicites empêcheraient exactement cette erreur (et d'autres, basées sur une simple erreur de frappe, qui, comme je l'ai dit, est en fait un problème extrêmement courant et chronophage, même si vous avez raison de dire que le problème est plus important en Perl. langues). Et la contradiction à laquelle je fais allusion est l'exigence d'explicitation du Zen, qui est corporellement jetée par la fenêtre ici.
Konrad Rudolph

40

Vous ne passez pas **locals()aux fonctions, n'est-ce pas ?

Comme Python n'a pas d'instruction "include" et que le selfparamètre est explicite et que les règles de portée sont assez simples, il est généralement très facile de pointer du doigt une variable et de dire d'où vient cet objet - sans lire d'autres modules et sans aucun type d'IDE (qui sont de toute façon limités en termes d'introspection, par le fait que le langage est très dynamique).

Le import *casse tout ça.

En outre, il a une possibilité concrète de cacher des bugs.

import os, sys, foo, sqlalchemy, mystuff
from bar import *

Maintenant, si le module de barre a l'un des attributs " os", " mystuff", etc ..., ils remplaceront ceux explicitement importés, et peuvent pointer vers des choses très différentes. Définir __all__dans bar est souvent sage - cela indique ce qui sera implicitement importé - mais il est toujours difficile de retracer l'origine des objets, sans lire et analyser le module bar et suivre ses importations. Un réseau de import *est la première chose que je corrige lorsque je prends possession d'un projet.

Ne vous méprenez pas: s'il import *manquait, je pleurerais pour l'avoir. Mais il doit être utilisé avec précaution. Un bon cas d'utilisation est de fournir une interface de façade sur un autre module. De même, l'utilisation d'instructions d'importation conditionnelle ou d'importations à l'intérieur d'espaces de noms de fonctions / classes nécessite un peu de discipline.

Je pense que dans les projets de taille moyenne à grande, ou les petits avec plusieurs contributeurs, un minimum d'hygiène est nécessaire en termes d'analyse statique - exécutant au moins pyflakes ou encore mieux un pylint correctement configuré - pour attraper plusieurs types de bugs avant ils arrivent.

Bien sûr, étant donné qu'il s'agit de python - n'hésitez pas à enfreindre les règles et à explorer - mais méfiez-vous des projets qui pourraient décupler, si le code source manque de discipline, ce sera un problème.


6
Python 2.x n'ont une déclaration « include ». Ça s'appelle . Heureusement, il est rarement utilisé et est parti en 3.x. execfile()
Sven Marnach

Que diriez-vous **vars()d'inclure des globaux si la fonction appelée est dans un autre fichier? : P
Solomon Ucko

16

C'est OK à faire from ... import *dans une session interactive.


Que diriez-vous à l'intérieur d'une doctestchaîne? Est-ce que le import *est interprété dans un "bac à sable" dans ce cas? Merci.
PatrickT

16

C'est parce que vous polluez l'espace de noms. Vous importerez toutes les fonctions et classes dans votre propre espace de noms, qui peuvent entrer en conflit avec les fonctions que vous définissez vous-même.

De plus, je pense que l'utilisation d'un nom qualifié est plus clair pour la tâche de maintenance; vous voyez sur la ligne de code elle-même d'où vient une fonction, vous pouvez donc consulter les documents beaucoup plus facilement.

Dans le module foo:

def myFunc():
    print 1

Dans votre code:

from foo import *

def doThis():
    myFunc() # Which myFunc is called?

def myFunc():
    print 2


9

Supposons que vous ayez le code suivant dans un module appelé foo:

import ElementTree as etree

puis dans votre propre module vous avez:

from lxml import etree
from foo import *

Vous avez maintenant un module difficile à déboguer qui semble contenir l'etree de lxml, mais qui contient vraiment ElementTree à la place.


7

Ce sont toutes de bonnes réponses. Je vais ajouter que lorsque vous apprenez à de nouvelles personnes à coder en Python, il import *est très difficile de gérer cela . Même si vous ou eux n'avez pas écrit le code, c'est toujours une pierre d'achoppement.

J'apprends aux enfants (environ 8 ans) à programmer en Python pour manipuler Minecraft. J'aime leur donner un environnement de codage utile pour travailler avec ( Atom Editor ) et enseigner le développement piloté par REPL (via bpython ). Dans Atom, je trouve que les astuces / complétion fonctionnent aussi efficacement que bpython. Heureusement, contrairement à certains autres outils d'analyse statistique, Atom n'est pas dupe import *.

Cependant, prenons cet exemple ... Dans ce wrapper, ils ont from local_module import *un tas de modules comprenant cette liste de blocs . Ignorons le risque de collisions d'espace de noms. Ce faisant, from mcpi.block import *ils font de cette liste entière de types obscurs de blocs quelque chose que vous devez examiner pour savoir ce qui est disponible. S'ils avaient plutôt utilisé from mcpi import block, vous pouvez taper walls = block.et une liste de saisie semi-automatique apparaîtra. Capture d'écran Atom.io


6

Compris les points valides que les gens mettent ici. Cependant, j'ai un argument selon lequel, parfois, "l'importation d'étoiles" n'est pas toujours une mauvaise pratique:

  • Quand je veux structurer mon code de telle manière que toutes les constantes vont dans un module appelé const.py:
    • Si je le fais import const, alors pour chaque constante, je dois la désigner comme const.SOMETHING, ce qui n'est probablement pas le moyen le plus pratique.
    • Si je le fais from const import SOMETHING_A, SOMETHING_B ..., alors évidemment c'est beaucoup trop verbeux et va à l'encontre du but de la structuration.
    • Je pense donc que dans ce cas, faire un from const import *peut être un meilleur choix.

4

C'est une pratique très MAUVAISE pour deux raisons:

  1. Lisibilité du code
  2. Risque de passer outre les variables / fonctions, etc.

Pour le point 1 : Voyons un exemple de ceci:

from module1 import *
from module2 import *
from module3 import *

a = b + c - d

Ici, en voyant le code ne sera obtenir une idée au sujet de quel module b, cet dappartient en réalité.

D'un autre côté, si vous le faites comme:

#                   v  v  will know that these are from module1
from module1 import b, c   # way 1
import module2             # way 2

a = b + c - module2.d
#            ^ will know it is from module2

C'est beaucoup plus propre pour vous, et la nouvelle personne qui rejoindra votre équipe aura une meilleure idée.

Pour le point 2 : disons les deux module1et module2ayez la variable comme b. Quand je fais:

from module1 import *
from module2 import *

print b  # will print the value from module2

Ici, la valeur de module1est perdue. Il sera difficile de déboguer pourquoi le code ne fonctionne pas même s'il best déclaré dans module1et j'ai écrit le code en attendant que mon code soit utilisémodule1.b

Si vous avez les mêmes variables dans différents modules et que vous ne souhaitez pas importer le module entier, vous pouvez même faire:

from module1 import b as mod1b
from module2 import b as mod2b

2

En guise de test, j'ai créé un module test.py avec 2 fonctions A et B, qui impriment respectivement "A 1" et "B 1". Après avoir importé test.py avec:

import test

. . . Je peux exécuter les 2 fonctions comme test.A () et test.B (), et "test" apparaît comme un module dans l'espace de noms, donc si j'édite test.py je peux le recharger avec:

import importlib
importlib.reload(test)

Mais si je fais ce qui suit:

from test import *

il n'y a pas de référence à "test" dans l'espace de noms, il n'y a donc aucun moyen de le recharger après une édition (pour autant que je sache), ce qui est un problème dans une session interactive. Considérant que l'un des éléments suivants:

import test
import test as tt

ajoutera "test" ou "tt" (respectivement) comme noms de module dans l'espace de noms, ce qui permettra le rechargement.

Si je fais:

from test import *

les noms «A» et «B» apparaissent dans l'espace de noms en tant que fonctions . Si j'édite test.py et que je répète la commande ci-dessus, les versions modifiées des fonctions ne sont pas rechargées.

Et la commande suivante provoque un message d'erreur.

importlib.reload(test)    # Error - name 'test' is not defined

Si quelqu'un sait comment recharger un module chargé avec "from module import *", veuillez poster. Sinon, ce serait une autre raison d'éviter le formulaire:

from module import *

2

Comme suggéré dans la documentation, vous ne devriez (presque) jamais utiliser import *dans le code de production.

Alors que l'importation à *partir d'un module est mauvaise, l' importation * à partir d'un package est encore pire. Par défaut, from package import *importe tous les noms définis par le package __init__.py, y compris tous les sous-modules du package chargés par les importinstructions précédentes .

Cependant, si le __init__.pycode d' un package définit une liste nommée __all__, elle est considérée comme la liste des noms de sous-modules qui doivent être importés en cas de from package import *rencontre.

Considérez cet exemple (en supposant qu'il n'y a pas de __all__défini dans sound/effects/__init__.py):

# anywhere in the code before import *
import sound.effects.echo
import sound.effects.surround

# in your module
from sound.effects import *

La dernière instruction importera les modules echoet surrounddans l'espace de noms actuel (éventuellement en remplaçant les définitions précédentes) car ils sont définis dans le sound.effectspackage lorsque l' importinstruction est exécutée.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.