PEP 8 dit:
- Les importations sont toujours placées en haut du fichier, juste après les commentaires et les docstrings de module, et avant les globales et les constantes du module.
À l'occasion, je viole PEP 8. Parfois, j'importe des choses à l'intérieur des fonctions. En règle générale, je fais cela s'il y a une importation qui n'est utilisée que dans une seule fonction.
Des opinions?
EDIT (la raison pour laquelle je pense que l'importation dans les fonctions peut être une bonne idée):
Raison principale: cela peut rendre le code plus clair.
from m import xxx
. Voyant m.xxx
dans la fonction m'en dit probablement plus. Selon ce qu'est m
: s'agit-il d'un module/package de premier niveau bien connu (import m
)? Ou s'agit-il d'un sous-module/package (from a.b.c import m
)?À long terme, je pense que vous apprécierez d'avoir la plupart de vos importations en haut du fichier, de cette façon, vous pouvez dire en un coup d'œil à quel point votre module est compliqué par ce qu'il doit importer.
Si j'ajoute du nouveau code à un fichier existant, je ferai généralement l'importation là où c'est nécessaire, puis si le code reste, je rendrai les choses plus permanentes en déplaçant la ligne d'importation en haut du fichier.
Un autre point, je préfère obtenir une exception ImportError
avant l'exécution de tout code - comme vérification de cohérence, c'est donc une autre raison d'importer en haut.
J'utilise pyChecker
pour vérifier les modules inutilisés.
Il y a deux fois où je viole PEP 8 à cet égard:
import pdb; pdb.set_trace()
C'est pratique b/c je ne veux pas mettre import pdb
en haut de chaque module, je voudrais peut-être déboguer, et il est facile de se rappeler de supprimer l'importation lorsque je supprime le point d'arrêt.En dehors de ces deux cas, c'est une bonne idée de tout mettre en haut. Cela rend les dépendances plus claires.
Voici les quatre cas d'utilisation d'importation que nous utilisons
import
(et from x import y
et import x as y
) au sommet
Choix pour l'importation. Au sommet.
import settings
if setting.something:
import this as foo
else:
import that as foo
Importation conditionnelle. Utilisé avec JSON, bibliothèques XML et similaires. Au sommet.
try:
import this as foo
except ImportError:
import that as foo
Importation dynamique. Jusqu'à présent, nous n'en avons qu'un exemple.
import settings
module_stuff = {}
module= __import__( settings.some_module, module_stuff )
x = module_stuff['x']
Notez que cette importation dynamique n'apporte pas de code, mais apporte des structures de données complexes écrites en Python. C'est un peu comme une donnée marinée, sauf que nous l'avons marinée à la main.
C'est aussi, plus ou moins, en haut d'un module
Voici ce que nous faisons pour rendre le code plus clair:
Gardez les modules courts.
Si j'ai toutes mes importations en haut du module, je dois y aller pour déterminer ce qu'est un nom. Si le module est court, c'est facile à faire.
Dans certains cas, avoir ces informations supplémentaires à proximité de l'endroit où un nom est utilisé peut rendre la fonction plus facile à comprendre. Si le module est court, c'est facile à faire.
Une chose à garder à l'esprit: les importations inutiles peuvent entraîner des problèmes de performances. Donc, si c'est une fonction qui sera appelée fréquemment, vous feriez mieux de placer l'importation en haut. Bien sûr, cela est une optimisation, donc s'il y a un cas valide à faire que l'importation à l'intérieur d'une fonction est plus clair que l'importation en haut d'un fichier, cela surpasse les performances dans la plupart des cas.
Si vous faites IronPython, on me dit qu'il est préférable d'importer des fonctions internes (car la compilation de code dans IronPython peut être lente). Ainsi, vous pourrez alors obtenir un moyen d'importer des fonctions internes. Mais à part cela, je dirais que cela ne vaut tout simplement pas la peine de lutter contre les conventions.
En règle générale, je fais cela s'il y a une importation qui n'est utilisée que dans une seule fonction.
Un autre point que j'aimerais souligner est que cela peut être un problème de maintenance potentiel. Que se passe-t-il si vous ajoutez une fonction qui utilise un module qui était auparavant utilisé par une seule fonction? Allez-vous vous rappeler d'ajouter l'importation en haut du fichier? Ou allez-vous analyser chaque fonction pour les importations?
FWIW, il y a des cas où il est logique d'importer à l'intérieur d'une fonction. Par exemple, si vous souhaitez définir la langue dans cx_Oracle, vous devez définir une variable d'environnement NLS _
LANG avant elle est importée. Ainsi, vous pouvez voir du code comme celui-ci:
import os
Oracle = None
def InitializeOracle(lang):
global Oracle
os.environ['NLS_LANG'] = lang
import cx_Oracle
Oracle = cx_Oracle
J'ai déjà enfreint cette règle pour les modules qui sont auto-testés. Autrement dit, ils ne sont normalement utilisés que pour le support, mais je leur définis un principal de sorte que si vous les exécutez seuls, vous pouvez tester leurs fonctionnalités. Dans ce cas, j'importe parfois getopt
et cmd
juste en principal, car je veux qu'il soit clair pour quelqu'un qui lit le code que ces modules n'ont rien à voir avec le fonctionnement normal du module et ne sont inclus que pour les tests.
Venant de la question sur chargement du module deux fois - Pourquoi pas les deux?
Une importation en haut du script indiquera les dépendances et une autre importation dans la fonction avec rendra cette fonction plus atomique, tout en ne causant apparemment aucun inconvénient de performances, car une importation consécutive est bon marché.
Tant que c'est import
et non from x import *
, vous devez les mettre en haut. Il ajoute un seul nom à l'espace de noms global et vous vous en tenez à PEP 8. De plus, si vous en avez besoin plus tard ailleurs, vous n'avez rien à déplacer.
Ce n'est pas grave, mais comme il n'y a presque aucune différence, je suggère de faire ce que dit PEP 8.
Jetez un œil à l'approche alternative utilisée dans sqlalchemy: injection de dépendance:
@util.dependencies("sqlalchemy.orm.query")
def merge_result(query, *args):
#...
query.Query(...)
Remarquez comment la bibliothèque importée est déclarée dans un décorateur et passée comme argument à la fonction!
Cette approche rend le code plus propre et fonctionne également 4,5 fois plus rapidement qu'une instruction import
!
Référence: https://Gist.github.com/kolypto/589e84fbcfb6312532658df2fabdb796