J'ai essayé de trouver un guide complet indiquant s'il est préférable d'utiliser import module
ou from module import
? Je viens juste de commencer avec Python et j'essaie de commencer avec les meilleures pratiques en tête.
En gros, j'espérais que quelqu'un pourrait partager ses expériences, quelles préférences d'autres développeurs ont et quel est le meilleur moyen d'éviter tout pièges sur la route?
La différence entre import module
et from module import foo
est principalement subjective. Choisissez celui que vous préférez et soyez cohérent dans votre utilisation. Voici quelques points pour vous aider à décider.
import module
import
. Il n'est pas nécessaire d'ajouter d'autres importations pour commencer à utiliser un autre élément du module.module.foo
dans votre code peut être fastidieux et redondant (l'ennui peut être minimisé en utilisant import module as mo
puis en tapant mo.foo
)from module import foo
foo
import
.foo
. Par exemple, ce que ceil()
fait par rapport à math.ceil()
est moins clair.Quelle que soit la méthode choisie, mais non utilise from module import *
.
Pour tout grand ensemble de code raisonnable, si vous import *
, vous le cimenterez probablement dans le module, sans possibilité de le supprimer. C’est parce qu’il est difficile de déterminer quels éléments utilisés dans le code proviennent de 'module', ce qui vous permet d’arriver facilement au point où vous pensez que vous n’utilisez plus import
, mais il est extrêmement difficile de etre sur.
Il y a un autre détail ici, non mentionné, lié à l'écriture dans un module. Cela n’est peut-être pas très courant, mais j'en ai eu besoin de temps en temps.
En raison de la manière dont les références et la liaison de noms fonctionnent en Python, si vous souhaitez mettre à jour un symbole dans un module, disons foo.bar, depuis l'extérieur de ce module, et que le code d'importation "voir" qui change, vous devez importer foo a certaine manière. Par exemple:
module foo:
bar = "apples"
module a:
import foo
foo.bar = "oranges" # update bar inside foo module object
module b:
import foo
print foo.bar # if executed after a's "foo.bar" assignment, will print "oranges"
Toutefois, si vous importez des noms de symboles au lieu de noms de modules, cela ne fonctionnera pas.
Par exemple, si je fais cela dans le module a:
from foo import bar
bar = "oranges"
Aucun code en dehors d'une barre ne verra "oranges" car mon réglage de barre affectait simplement le nom "bar" à l'intérieur du module a, il ne "pénétrait" pas dans "l'objet module foo et ne mettait pas à jour sa" barre ".
Même si beaucoup de gens ont déjà expliqué import
vs import from
, je voudrais essayer d'expliquer un peu plus ce qui se passe sous le capot et où se trouvent tous les changements.
import foo
:Importe foo
et crée une référence à ce module dans l'espace de noms actuel. Ensuite, vous devez définir le chemin du module terminé pour accéder à un attribut ou à une méthode particulière à partir de l'intérieur du module.
Par exemple. foo.bar
mais pas bar
from foo import bar
:Importe foo
et crée des références à tous les membres répertoriés (bar
). Ne définit pas la variable foo
.
Par exemple. bar
mais pas baz
ni foo.baz
from foo import *
:Importe foo
et crée des références à tous les objets publics définis par ce module dans l'espace de nom actuel (tout ce qui est répertorié dans __all__
si __all__
existe, sinon tout ce qui ne commence pas par _
). Ne définit pas la variable foo
.
Par exemple. bar
et baz
mais pas _qux
ou foo._qux
.
Voyons maintenant quand nous faisons import X.Y
:
>>> import sys
>>> import os.path
Vérifiez sys.modules
avec le nom os
et os.path
:
>>> sys.modules['os']
<module 'os' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/os.pyc'>
>>> sys.modules['os.path']
<module 'posixpath' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
Vérifiez globals()
et locals()
l'espace de nom dicté avec os
et os.path
:
>>> globals()['os']
<module 'os' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/os.pyc'>
>>> locals()['os']
<module 'os' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/os.pyc'>
>>> globals()['os.path']
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'os.path'
>>>
Dans l'exemple ci-dessus, nous avons constaté que seul os
est inséré dans les espaces de noms local et global. Donc, nous devrions pouvoir utiliser:
>>> os
<module 'os' from
'/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/os.pyc'>
>>> os.path
<module 'posixpath' from
'/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
>>>
Mais pas path
.
>>> path
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'path' is not defined
>>>
Une fois que vous avez supprimé le os
de l'espace de noms locals (), vous ne pourrez plus accéder à os
ainsi qu'à os.path
bien qu'ils existent dans sys.modules:
>>> del locals()['os']
>>> os
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'os' is not defined
>>> os.path
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'os' is not defined
>>>
import from
:from
:>>> import sys
>>> from os import path
sys.modules
avec os
et os.path
:>>> sys.modules['os']
<module 'os' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/os.pyc'>
>>> sys.modules['os.path']
<module 'posixpath' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
Nous avons trouvé que dans sys.modules
nous avions retrouvé la même chose que nous avions précédemment en utilisant import name
OK, vérifions à quoi ça ressemble dans locals()
et globals()
noms d'espace de nom:
>>> globals()['path']
<module 'posixpath' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
>>> locals()['path']
<module 'posixpath' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
>>> globals()['os']
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'os'
>>>
Vous pouvez y accéder en utilisant le nom path
pas par os.path
:
>>> path
<module 'posixpath' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
>>> os.path
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'os' is not defined
>>>
Supprimons 'chemin' de locals()
:
>>> del locals()['path']
>>> path
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'path' is not defined
>>>
Un dernier exemple utilisant un alias:
>>> from os import path as HELL_BOY
>>> locals()['HELL_BOY']
<module 'posixpath' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
>>> globals()['HELL_BOY']
<module 'posixpath' from /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
>>>
Et pas de chemin défini:
>>> globals()['path']
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'path'
>>>
Les deux moyens sont pris en charge pour une raison: il y a des moments où l’une est plus appropriée que l’autre.
import module
: Bien quand vous utilisez beaucoup de bits du module. L'inconvénient est que vous devez qualifier chaque référence avec le nom du module.
from module import ...
: Les éléments importés sont utilisables directement sans préfixe de nom de module. L'inconvénient est que vous devez répertorier chaque chose que vous utilisez et que le code ne précise pas d'où provient quelque chose.
Ce qui à utiliser dépend de ce qui rend le code clair et lisible, et a beaucoup à faire avec les préférences personnelles. Je me penche généralement vers import module
parce que, dans le code, il est très clair d'où vient un objet ou une fonction. J'utilise from module import ...
lorsque j'utilise un objet/une fonction a lot dans le code.
Personnellement, j'utilise toujours
from package.subpackage.subsubpackage import module
puis accéder à tout comme
module.function
module.modulevar
etc. La raison en est qu’en même temps, vous avez une courte invocation et vous définissez clairement l’espace de nom de module de chaque routine, ce qui est très utile si vous devez rechercher l’utilisation d’un module donné dans votre source.
Inutile de dire que n'utilisez pas l'import *, car il pollue votre espace de noms et il ne vous dit pas d'où vient une fonction donnée (de quel module)
Bien sûr, vous pouvez avoir des problèmes si vous avez le même nom de module pour deux modules différents dans deux packages différents, comme
from package1.subpackage import module
from package2.subpackage import module
dans ce cas, bien sûr, vous rencontrez des problèmes, mais il y a alors une forte indication que votre présentation de paquet est défectueuse, et vous devez la repenser.
import module
Il est préférable d’utiliser de nombreuses fonctions du module.
from module import function
Il est préférable d’éviter de polluer l’espace de noms global avec toutes les fonctions et tous les types d’un module lorsque vous n’avez besoin que de function
.
Voici une autre différence non mentionnée. Ceci est copié textuellement de http://docs.python.org/2/tutorial/modules.html
Notez que lorsque vous utilisez
from package import item
l'élément peut être soit un sous-module (ou un sous-package) du package, soit un autre nom défini dans le package, tel qu'une fonction, une classe ou une variable. L'instruction d'importation teste d'abord si l'élément est défini dans le package; sinon, il suppose qu'il s'agit d'un module et tente de le charger. S'il ne parvient pas à le trouver, une exception ImportError est générée.
Au contraire, lorsque vous utilisez une syntaxe telle que
import item.subitem.subsubitem
chaque article sauf le dernier doit être un colis; Le dernier élément peut être un module ou un package, mais ne peut pas être une classe, une fonction ou une variable définie dans l’élément précédent.
Je viens de découvrir une différence plus subtile entre ces deux méthodes.
Si le module foo
utilise une importation suivante:
from itertools import count
Ensuite, le module bar
peut utiliser par erreur count
comme s'il était défini dans foo
et non dans itertools
:
import foo
foo.count()
Si foo
utilise:
import itertools
l'erreur est toujours possible, mais moins probable. bar
doit:
import foo
foo.itertools.count()
Cela m'a causé des ennuis. J'ai eu un module qui par erreur a importé une exception d'un module qui ne l'a pas défini, l'a seulement importé d'un autre module (en utilisant from module import SomeException
). Lorsque l'importation n'était plus nécessaire et supprimée, le module incriminé était cassé.
import package
import module
Avec import
, le jeton doit être un module (un fichier contenant les commandes Python) ou un package (un dossier du sys.path
contenant un fichier __init__.py
.).
Quand il y a des sous-paquets:
import package1.package2.package
import package1.package2.module
la configuration requise pour le dossier (package) ou le fichier (module) est identique, mais le dossier ou le fichier doit se trouver dans package2
qui doit figurer dans package1
, et package1
et package2
doit contenir les fichiers __init__.py
. https://docs.python.org/2/tutorial/modules.html
Avec le style d'importation from
:
from package1.package2 import package
from package1.package2 import module
le package ou le module entre l'espace de noms du fichier contenant l'instruction import
sous la forme module
(ou package
) au lieu de package1.package2.module
. Vous pouvez toujours vous connecter à un nom plus pratique:
a = big_package_name.subpackage.even_longer_subpackage_name.function
Seul le style d'importation from
vous permet de nommer une fonction ou une variable particulière:
from package3.module import some_function
est autorisé, mais
import package3.module.some_function
n'est pas autorisé.
Puisque je suis aussi un débutant, je vais essayer d’expliquer cela d’une manière simple: En Python, nous avons trois types d’instructions import
qui sont:
1. Importations génériques:
import math
ce type d'importation est mon préféré, le seul inconvénient de cette technique d'importation est que si vous avez besoin d'utiliser une fonction du module, vous devez utiliser la syntaxe suivante:
math.sqrt(4)
bien sûr, cela augmente l'effort de dactylographie, mais en tant que débutant, cela vous aidera à garder une trace du module et de la fonction qui lui est associée (un bon éditeur de texte réduira considérablement l'effort de dactylographie et est recommandé) .
L'effort de frappe peut être encore réduit en utilisant cette instruction d'importation:
import math as m
maintenant, au lieu d'utiliser math.sqrt()
, vous pouvez utiliser m.sqrt()
.
2. Importations de fonctions:
from math import sqrt
, ce type d'importation convient mieux si votre code n'a besoin d'accéder qu'à une ou plusieurs fonctions du module, mais que pour utiliser tout nouvel élément du module, vous devez mettre à jour la déclaration d'importation.
3. Importations universelles:
from math import *
Bien qu'il réduise considérablement les efforts de frappe, il n'est toutefois pas recommandé, car votre code sera rempli de différentes fonctions du module et leur nom pourrait entrer en conflit avec le nom des fonctions définies par l'utilisateur. exemple:
Pour ajouter à ce que les gens ont dit à propos de from x import *
: outre qu’il est plus difficile de dire d’où viennent les noms, cela jette des correcteurs de code comme Pylint. Ils rapporteront ces noms en tant que variables non définies.
Ma propre réponse à cette question dépend principalement du premier, du nombre de modules que je vais utiliser. Si je n’en utilise qu’un ou deux, je vais souvent utiliser from
... import
dans la mesure où le nombre de frappes au clavier est réduit dans le reste du fichier, mais si je vais utiliser plusieurs modules, je préfère simplement import
car cela signifie que chaque référence de module est auto-documentée. Je peux voir d'où vient chaque symbole sans avoir à chercher.
Habituellement, je préfère le style d'auto-documentation de l'importation brut et ne change qu'en importation lorsque le nombre de fois que je dois taper le nom du module dépasse 10 à 20, même s'il n'y a qu'un seul module importé.
L'une des différences significatives que j'ai découvertes et dont étonnamment personne n'a parlé est l'utilisation d'une importation simple vous pouvez accéder à private variable
et private functions
à partir du module importé, ce qui n'est pas possible avec from-import déclaration.
Code en image:
public_variable = 42
_private_variable = 141
def public_function():
print("I'm a public function! yay!")
def _private_function():
print("Ain't nobody accessing me from another module...usually")
import settings
print (settings._private_variable)
print (settings.public_variable)
settings.public_function()
settings._private_function()
# Prints:
# 141
# 42
# I'm a public function! yay!
# Ain't nobody accessing me from another module...usually
from settings import *
#print (_private_variable) #doesn't work
print (public_variable)
public_function()
#_private_function() #doesn't work
Je voudrais ajouter à cela, il y a quelque chose à considérer lors des appels d'importation:
J'ai la structure suivante:
mod/
__init__.py
main.py
a.py
b.py
c.py
d.py
main.py:
import mod.a
import mod.b as b
from mod import c
import d
dis.dis montre la différence:
1 0 LOAD_CONST 0 (-1)
3 LOAD_CONST 1 (None)
6 IMPORT_NAME 0 (mod.a)
9 STORE_NAME 1 (mod)
2 12 LOAD_CONST 0 (-1)
15 LOAD_CONST 1 (None)
18 IMPORT_NAME 2 (b)
21 STORE_NAME 2 (b)
3 24 LOAD_CONST 0 (-1)
27 LOAD_CONST 2 (('c',))
30 IMPORT_NAME 1 (mod)
33 IMPORT_FROM 3 (c)
36 STORE_NAME 3 (c)
39 POP_TOP
4 40 LOAD_CONST 0 (-1)
43 LOAD_CONST 1 (None)
46 IMPORT_NAME 4 (mod.d)
49 LOAD_ATTR 5 (d)
52 STORE_NAME 5 (d)
55 LOAD_CONST 1 (None)
En fin de compte, ils ont le même aspect (STORE_NAME est le résultat dans chaque exemple), mais il convient de le noter si vous devez prendre en compte les quatre importations circulaires suivantes:
foo/
__init__.py
a.py
b.py
a.py:
import foo.b
b.py:
import foo.a
>>> import foo.a
>>>
Cela marche
bar/
__init__.py
a.py
b.py
a.py:
import bar.b as b
b.py:
import bar.a as a
>>> import bar.a
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "bar\a.py", line 1, in <module>
import bar.b as b
File "bar\b.py", line 1, in <module>
import bar.a as a
AttributeError: 'module' object has no attribute 'a'
Pas de dé
baz/
__init__.py
a.py
b.py
a.py:
from baz import b
b.py:
from baz import a
>>> import baz.a
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "baz\a.py", line 1, in <module>
from baz import b
File "baz\b.py", line 1, in <module>
from baz import a
ImportError: cannot import name a
Problème similaire ... mais clairement de x import y n’est pas identique à import import x.y à y
qux/
__init__.py
a.py
b.py
a.py:
import b
b.py:
import a
>>> import qux.a
>>>
Celui-ci fonctionne aussi
Module d'importation - Vous n'avez pas besoin d'efforts supplémentaires pour extraire une autre chose du module. Il présente des inconvénients tels que le typage redondant
Importation de module depuis - Moins de saisie et plus de contrôle sur les éléments d’un module auxquels vous pouvez accéder. Pour utiliser un nouvel élément du module, vous devez mettre à jour votre déclaration d’importation.