Bonnes pratiques pour importer un module externe en python

2018-10-17 python python-2.7

Permettez-moi de poser la question par un exemple simplifié. Supposons que j'ai un script python2 appelé example.py dans un répertoire avec un autre script que j'ai écrit appelé utils.py. Dans example.py, je dois importer un module externe qui est placé sous le chemin /A/B/external.py. «A» et «B» ne sont que des dossiers, pas des packages (sans __ init__.py). Enfin, supposons qu'il existe également un fichier utils.py sous / A / B / et qu'il soit importé par external.py.

Si j'importe le module externe comme je le connais, je ferai:

import sys
sys.path.append('/A/B/')
import external

le problème est que quand j'essaierai d'importer mon module utils, python le trouvera dans sys.modules dict (puisque externe l'a importé) et n'importera donc pas mon script mais seulement celui sous / A / B qui était déjà importé.

Maintenant, il existe des solutions de contournement. Je peux changer le nom du module, ou mettre le module externe dans un paquet, etc. Mais tout cela semble sale. Je n'ai pas pu trouver quelle est la meilleure pratique «pythonique» pour faire de telles choses. Comme certains d'entre vous pourraient le deviner, cela pourrait conduire à des bogues très ennuyeux avec des cas plus complexes. De plus, la façon dont je suis familier n'est pas acceptable par PEP8 car il y a des commandes d'importation qui ne sont pas en haut du module.

En conclusion, je recherche les meilleures pratiques pour faire de telles choses, merci.

Answers

Bien que presque deux ans se soient écoulés, je veux décrire la bonne réponse pour autant que je la comprends maintenant. TL; DR: La meilleure approche est d'éviter de manipuler sys.path (!) Et d'utiliser à la place des mécanismes d'empaquetage de distribution.

Tout d'abord, faisons la distinction entre le package de distribution et le package d'importation. Un package d'importation est essentiellement un répertoire qui contient des modules pythoniques (c'est-à-dire des fichiers .py / .pyc) et un fichier __init__.py pour déclarer que ce dossier est bien un package. Dans l'exemple de la question, il s'agit du répertoire utils.py example.py et utils.py . En opposition à cela, un package de distribution est:

Un fichier d'archive versionné qui contient des packages Python, des modules et d'autres fichiers de ressources utilisés pour distribuer une version.

sources: guide de l'utilisateur PyPA , glossaire .

Un autre terme qui devrait être connu est le script . Un script python est le fichier python __main__ , qui est directement exécuté via l'interpréteur (tandis que les autres fichiers python sont appelés modules ). source: documentation de python .

Dans votre propre package d'importation, vous ne devez pas éditer sys.path car le fichier de script importe les modules par rapport à l'emplacement de son fichier, et c'est le comportement souhaité. Si vous avez l'intention d'utiliser un autre module de l'extérieur de votre package d'importation (et laissez-moi préciser que ce n'est pas le cas que vous importez d'un autre package d'importation qui se trouve dans votre package d'importation actuel, c'est un comportement normal et fonctionne bien), alors vous devez l'importer en tant que package de distribution installé.

Ce que je veux dire par là, c'est que le code externe (dans l'exemple, le module external.py qui se trouve sous A / B /) devrait être disponible en tant que package de distribution (ses responsables devrait le télécharger en tant que package vers un mécanisme de distribution, par exemple PyPi , et cela pourrait être vous, mais en tant que développeur de package). Ensuite, en tant qu'utilisateur du package externe, vous devez l'installer (par exemple avec pip install sur le fichier wheel de ce package de distribution externe) et ensuite il sera ajouté et géré par votre environnement afin que vous puissiez import external fichier import external et cela fonctionnerait sans collisions.

Related