Question Importer un module à partir d'un chemin relatif


Comment importer un module Python en fonction de son chemin relatif?

Par exemple, si dirFoo contient Foo.py et dirBar, et dirBar contient Bar.py, comment importer Bar.py dans Foo.py?

Voici une représentation visuelle:

dirFoo\
    Foo.py
    dirBar\
        Bar.py

Foo souhaite inclure Bar, mais la restructuration de la hiérarchie des dossiers n'est pas une option.


703
2017-11-10 21:28


origine


Réponses:


En supposant que vos deux répertoires sont de vrais paquets Python (ont le __init__.py fichier à l'intérieur d'eux), voici une solution sûre pour l'inclusion de modules par rapport à l'emplacement du script.

Je suppose que vous voulez faire cela, car vous devez inclure un ensemble de modules avec votre script. Je l'utilise en production dans plusieurs produits et fonctionne dans de nombreux scénarios spéciaux comme: les scripts appelés depuis un autre répertoire ou exécutés avec python s'exécutent au lieu d'ouvrir un nouvel interpréteur.

 import os, sys, inspect
 # realpath() will make your script run, even if you symlink it :)
 cmd_folder = os.path.realpath(os.path.abspath(os.path.split(inspect.getfile( inspect.currentframe() ))[0]))
 if cmd_folder not in sys.path:
     sys.path.insert(0, cmd_folder)

 # Use this if you want to include modules from a subfolder
 cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],"subfolder")))
 if cmd_subfolder not in sys.path:
     sys.path.insert(0, cmd_subfolder)

 # Info:
 # cmd_folder = os.path.dirname(os.path.abspath(__file__)) # DO NOT USE __file__ !!!
 # __file__ fails if the script is called in different ways on Windows.
 # __file__ fails if someone does os.chdir() before.
 # sys.argv[0] also fails, because it doesn't not always contains the path.

En prime, cette approche vous permet de forcer Python à utiliser votre module à la place de ceux installés sur le système.

Attention! Je ne sais pas vraiment ce qui se passe quand le module actuel est à l'intérieur d'un egg fichier. Cela échoue probablement aussi.


312
2018-05-23 14:00



Assurez-vous que dirBar a le __init__.py fichier - ceci crée un répertoire dans un paquet Python.


316
2017-11-10 21:33



Vous pouvez également ajouter le sous-répertoire à votre chemin Python pour qu'il soit importé en tant que script normal.

import sys
sys.path.insert(0, <path to dirFoo>)
import Bar

245
2017-11-10 22:04



import os
import sys
lib_path = os.path.abspath(os.path.join(__file__, '..', '..', '..', 'lib'))
sys.path.append(lib_path)

import mymodule

109
2017-11-26 10:21



Faites simplement des choses simples pour importer le fichier .py à partir d'un dossier différent.

Disons que vous avez un répertoire comme:

lib/abc.py

Ensuite, gardez juste un fichier vide dans le dossier lib comme nommé

__init__.py

Et puis utilisez

from lib.abc import <Your Module name>

Garder le __init__.py fichier dans chaque dossier de la hiérarchie du module d'importation.


94
2017-12-09 10:40



Si vous structurez votre projet de cette façon:

src\
  __init__.py
  main.py
  dirFoo\
    __init__.py
    Foo.py
  dirBar\
    __init__.py
    Bar.py

Ensuite, à partir de Foo.py, vous devriez être capable de faire:

import dirFoo.Foo

Ou:

from dirFoo.Foo import FooObject

Par le commentaire de Tom, cela exige que le src dossier est accessible soit via site_packages ou votre chemin de recherche. Aussi, comme il le dit, __init__.py est implicitement importé lors de la première importation d'un module dans ce répertoire / répertoire. Typiquement __init__.py est simplement un fichier vide.


77
2017-11-10 21:46



La méthode la plus simple consiste à utiliser sys.path.append ().

Cependant, vous pourriez également être intéressé par lutin module. Il donne accès aux fonctions d'importation internes.

# mod_name is the filename without the .py/.pyc extention
py_mod = imp.load_source(mod_name,filename_path) # Loads .py file
py_mod = imp.load_compiled(mod_name,filename_path) # Loads .pyc file 

Cela peut être utilisé pour charger des modules dynamiquement lorsque vous ne connaissez pas le nom d'un module.

Je l'ai utilisé dans le passé pour créer une interface de type plugin pour une application, où l'utilisateur écrirait un script avec des fonctions spécifiques à l'application, et déposerait simplement son script dans un répertoire spécifique.

En outre, ces fonctions peuvent être utiles:

imp.find_module(name[, path])
imp.load_module(name, file, pathname, description)

44
2017-11-12 01:56



C'est le PEP pertinent:

http://www.python.org/dev/peps/pep-0328/

En particulier, supposer que dirFoo est un répertoire de dirBar ...

Dans dirFoo \ Foo.py:

from ..dirBar import Bar

40
2017-11-10 22:22



Le moyen le plus simple sans modification de votre script est de définir la variable d'environnement PYTHONPATH. Parce que sys.path est initialisé à partir de ces emplacements:

  1. Le répertoire contenant le script d'entrée (ou le annuaire).
  2. PYTHONPATH (une liste de noms de répertoires, avec le même syntaxe comme variable shell PATH).
  3. La valeur par défaut dépendante de l'installation.

Il suffit de courir:

export PYTHONPATH=/absolute/path/to/your/module

Vous sys.path contiendra le chemin ci-dessus, comme montré ci-dessous:

print sys.path

['', '/absolute/path/to/your/module', '/usr/lib/python2.7', '/usr/lib/python2.7/plat-linux2', '/usr/lib/python2.7/lib-tk', '/usr/lib/python2.7/lib-old', '/usr/lib/python2.7/lib-dynload', '/usr/local/lib/python2.7/dist-packages', '/usr/lib/python2.7/dist-packages', '/usr/lib/python2.7/dist-packages/PIL', '/usr/lib/python2.7/dist-packages/gst-0.10', '/usr/lib/python2.7/dist-packages/gtk-2.0', '/usr/lib/pymodules/python2.7', '/usr/lib/python2.7/dist-packages/ubuntu-sso-client', '/usr/lib/python2.7/dist-packages/ubuntuone-client', '/usr/lib/python2.7/dist-packages/ubuntuone-control-panel', '/usr/lib/python2.7/dist-packages/ubuntuone-couch', '/usr/lib/python2.7/dist-packages/ubuntuone-installer', '/usr/lib/python2.7/dist-packages/ubuntuone-storage-protocol']

20
2018-02-10 23:21



À mon avis, le meilleur choix est de mettre __ init __.py dans le dossier et appelez le fichier avec

from dirBar.Bar import *

Il n'est pas recommandé d'utiliser sys.path.append () car quelque chose pourrait mal fonctionner si vous utilisez le même nom de fichier que le paquet python existant. Je n'ai pas testé cela, mais ce sera ambigu.


11
2017-09-15 05:02



Le moyen rapide et sale pour les utilisateurs de Linux

Si vous ne faites que bricoler et ne vous souciez pas des problèmes de déploiement, vous pouvez utiliser un lien symbolique (en supposant que votre système de fichiers le supporte) pour rendre le module ou le package directement visible dans le dossier du module demandeur.

ln -s (path)/module_name.py

ou

ln -s (path)/package_name

Note: Un "module" est n'importe quel fichier avec une extension .py et un "paquet" est n'importe quel dossier qui contient le fichier __init__.py (qui peut être un fichier vide). Du point de vue de l'utilisation, les modules et les paquets sont identiques - les deux exposent leurs "définitions et déclarations" contenues comme demandé via le import commander.

Voir: http://docs.python.org/2/tutorial/modules.html


10
2017-12-20 01:07