web-dev-qa-db-fra.com

Effet de l'utilisation de sys.path.insert (0, chemin) et de sys.path (ajout) lors du chargement de modules

Je rencontrais récemment un problème avec un python ImportError, où le module a été trouvé lors de son exécution sur mon ordinateur local mais introuvable sur le serveur CI. J'ai résolu ce problème en échangeant sys.path.append(path) dans mon script avec sys.path.insert(0, path)path est l'emplacement du module de chaîne.

Puisqu'il s'agit de mon module et non d'un paquet installé ( question connexe ), pourquoi l'ordre des chemins corrige-t-il ce problème?

36
Michael Barton

Parce que python vérifie les répertoires par ordre séquentiel à partir du premier répertoire de sys.path liste, jusqu'à ce qu'il trouve le .py fichier qu'il cherchait.

Idéalement, le répertoire en cours ou le répertoire du script est le premier, toujours le premier élément de la liste, à moins que vous ne le modifiiez, comme vous l'avez fait. De documentation -

Initialisé au démarrage du programme, le premier élément de cette liste, chemin [0], est le répertoire contenant le script utilisé pour appeler l'interprète Python. Si le répertoire de script n'est pas disponible ( Par exemple, si l'interpréteur est appelé de manière interactive ou si le script est lu à partir de l'entrée standard), chemin [0] est la chaîne vide qui indique à Python de rechercher d'abord les modules dans le répertoire en cours. Remarque le répertoire de script est inséré avant les entrées insérées à la suite de PYTHONPATH.

Donc, très probablement, vous avez eu un .py fichier portant le même nom que le module à partir duquel vous essayez d'importer, dans le répertoire en cours (à partir duquel le script a été exécuté).

En outre, une chose à noter à propos de ImportErrors, disons que l'erreur d'importation indique - ImportError: No module named main - cela ne signifie pas que le main.py est écrasé, non, si cela était écrasé, nous n'aurions aucun problème à essayer de le lire. Certains modules ci-dessus ont été remplacés par un fichier .py ou un autre fichier.

Exemple -

Ma structure de répertoire ressemble à -

 - test
    - shared
         - __init__.py
         - phtest.py
  - testmain.py

Maintenant de testmain.py , J'appelle from shared import phtest , ça fonctionne bien.

Maintenant, disons que je présente un shared.py dans test directory`, exemple -

 - test
    - shared
         - __init__.py
         - phtest.py
  - testmain.py 
  - shared.py

Maintenant, quand j'essaie de faire from shared import phtest de testmain.py, Je vais avoir l'erreur -

ImportError: cannot import name 'phtest'

Comme vous pouvez le voir ci-dessus, le fichier à l'origine du problème est shared.py , ne pas phtest.py.

24
Anand S Kumar

Je suis assez débutant en Python et j'ai trouvé que la réponse d'Anand était très bonne mais assez compliquée pour moi, alors j'essaie de reformuler:

1) Les méthodes insert et append ne sont pas spécifiques à sys.path Et, comme dans d'autres langues, elles ajoutent un élément dans une liste ou un tableau et:
* append(item) ajouter item à la fin de la liste,
* insert(n, item) insère le item à la nième position dans la liste (0 au début, 1 après le premier élément, etc ...).

2) Comme Anand l'a dit, python), recherchez les fichiers d'importation dans chaque répertoire du chemin, dans l'ordre du chemin, de la manière suivante:
* Si vous n’avez pas de conflit de nom de fichier, l’ordre du chemin n’a aucune incidence,
* Si vous vous occupez d’une fonction déjà définie dans le chemin et que vous utilisez append pour ajouter votre chemin, vous n’obtiendrez pas votre fonction mais celle prédéfinie.

Mais je pense qu'il vaut mieux utiliser append et non pas insert pour ne pas surcharger le comportement standard de Python et utiliser des noms non ambigus pour vos fichiers et méthodes.

24
geekobi