Importer un module à partir d'un chemin relatif

Comment puis-je importer un module Python étant donné son chemin relatif?

Par exemple, si dirFoo contient Foo.py et dirBar , et dirBar contient Bar.py , comment puis-je importer Bar.py en 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.

706
demandé sur Peter Mortensen 2008-11-11 00:28:48

23 réponses

en supposant que vos deux répertoires sont de vrais paquets Python (ils contiennent le fichier __init__.py ), voici une solution sûre pour inclure des modules relativement à l'emplacement du script.

je suppose que vous voulez le faire, parce que vous avez besoin d'un ensemble de modules avec votre script. Je l'utilise en production dans plusieurs produits et fonctionne dans de nombreux scénarios spéciaux tels que: scripts appelés à partir d'un autre répertoire ou exécutés avec python execute au lieu de l'ouverture d'un nouvel interprète.

 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 bonus, cette approche vous permet de forcer Python à utiliser votre module au lieu de ceux installés sur le système.

Attention! Je ne sais pas vraiment ce qui se passe quand le module courant est dans un fichier egg . Il échoue probablement aussi.

314
répondu sorin 2017-08-28 13:55:41

assurez-vous que dirBar a le fichier __init__.py -- Cela fait d'un répertoire un paquet Python.

317
répondu S.Lott 2008-11-10 21:33:33

vous pouvez aussi ajouter le sous-répertoire à votre chemin Python pour qu'il soit importé comme un script normal.

import sys
sys.path.insert(0, <path to dirFoo>)
import Bar
245
répondu Andrew Cox 2018-02-07 21:42:26
import os
import sys
lib_path = os.path.abspath(os.path.join(__file__, '..', '..', '..', 'lib'))
sys.path.append(lib_path)

import mymodule
110
répondu lefakir 2018-01-26 06:35:49

Juste faire des choses simples pour importer le .py fichier à partir d'un autre dossier.

disons que vous avez un répertoire comme:

lib/abc.py

alors il suffit de garder un fichier vide dans le dossier lib comme nommé

__init__.py

et ensuite utiliser

from lib.abc import <Your Module name>

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

94
répondu Deepak 'Kaseriya' 2017-08-28 14:17:21

si vous structurez votre projet de cette façon:

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

puis de Foo.py vous devriez être en mesure de faire:

import dirFoo.Foo

Ou:

from dirFoo.Foo import FooObject

selon le commentaire de Tom, cela nécessite que le dossier src soit accessible via site_packages ou votre chemin de recherche. En outre, comme il le mentionne, __init__.py est implicitement importé lorsque vous importez un module dans ce paquet/répertoire. Typiquement __init__.py est simplement un fichier vide.

77
répondu bouvard 2017-08-28 13:57:24

la méthode la plus facile est d'utiliser sys.chemin.annexer.)(

cependant, vous pouvez également être intéressé par le module imp . 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 

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

j'ai utilisé ceci dans le passé pour créer une interface de type plugin à une application, où l'utilisateur écrirait un script avec fonctions spécifiques à l'application, et il suffit de déposer le script dans un répertoire spécifique.

Aussi, ces fonctions peuvent être utiles:

imp.find_module(name[, path])
imp.load_module(name, file, pathname, description)
44
répondu monkut 2008-11-12 01:56:51

il s'agit de la PEP pertinente:

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

en particulier, présumant que dirFoo est un répertoire à partir de dirBar...

In dirFoo\Foo.py:

from ..dirBar import Bar
41
répondu Peter Crabtree 2008-11-10 22:22:47

la façon la plus simple sans aucune modification de votre script est de définir la variable d'environnement PYTHONPATH. Parce que sys.le chemin est initialisé à partir de ces emplacements:

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

Just exécuter:

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

Vous sys.le chemin contiendra le chemin ci-dessus, comme indiqué 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']
21
répondu James Gan 2017-08-28 14:06:14

À 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.chemin.append() parce que quelque chose pourrait mal tourné si vous utilisez le même nom de fichier que le paquet python. Je ne l'ai pas testé, mais ce sera ambigu.

11
répondu jhana 2010-09-15 05:02:52

le chemin rapide et sale pour les utilisateurs de Linux

si vous êtes juste en train de bricoler et que vous 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 paquet 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 un .PY extension et a "package" est un 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 -- tous deux exposent leurs "définitions et énoncés" contenus comme demandé par la commande import .

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

10
répondu nobar 2012-12-20 01:07:43
from .dirBar import Bar

au lieu de:

from dirBar import Bar

juste au cas où il pourrait y avoir un autre dirBar installé et confondre une foo.py lecteur.

9
répondu jgomo3 2012-08-07 14:48:30

pour ce cas d'importation Bar.py en Foo.py, d'abord je transformerais ces dossiers en paquets Python comme ceci:

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

alors je le ferais comme ceci en Foo.py:

from .dirBar import Bar

si je voulais que l'espacenom ressemble à un Bar. quelque soit , ou

"
from . import dirBar

si je voulais le nom dirBar.Bar. quel que soit . Ce second cas est utile si vous avez plusieurs modules sous le paquet dirBar.

7
répondu Al Conrad 2017-08-28 14:07:09

Ajouter un __init__.py fichier:

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

puis ajouter ce code au début de Foo.py:

import sys
sys.path.append('dirBar')
import Bar
6
répondu Josh 2010-09-05 07:45:00

par rapport sys.exemple de chemin:

# /lib/my_module.py
# /src/test.py


if __name__ == '__main__' and __package__ is None:
    sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '../lib')))
import my_module

basé sur cette réponse .

5
répondu Der_Meister 2017-05-23 11:47:26

bien, comme vous le mentionnez, habituellement vous voulez avoir accès à un dossier avec vos modules relatifs à l'endroit où votre script principal est exécuté, donc vous n'avez qu'à les importer.

Solution:

j'ai le script dans D:/Books/MyBooks.py et certains modules (comme oldies.py). Je dois importer du sous-répertoire D:/Books/includes :

import sys,site
site.addsitedir(sys.path[0] + '\includes')
print (sys.path)  # Just verify it is there
import oldies

placez un print('done') dans oldies.py , donc vous vérifiez que tout va bien. De cette façon fonctionne toujours parce que par la définition de Python sys.path initialisée au démarrage du programme, le premier élément de cette liste, path[0] , est le répertoire contenant le script qui a été utilisé pour invoquer L'interpréteur Python.

si le répertoire de script n'est pas disponible (par exemple si l'interpréteur est invoqué de manière interactive ou si le script est lu à partir d'une entrée standard), path[0] est la chaîne vide, qui dirige Python vers les modules de recherche dans le répertoire courant en premier. Notez que le répertoire script est inséré avant les entrées insérées à la suite de PYTHONPATH .

4
répondu Avenida Gez 2017-08-28 14:09:19

une autre solution serait d'installer le paquet PY-require puis d'utiliser ce qui suit dans Foo.py

import require
Bar = require('./dirBar/Bar')
3
répondu Niklas R 2016-08-06 21:26:58

regardez le module pkgutil de la bibliothèque standard. Il peut vous aider à faire ce que vous voulez.

2
répondu Mihail Mihaylov 2011-02-09 15:19:55

Voici une façon d'importer un fichier à partir d'un niveau au-dessus, en utilisant le chemin relatif.

essentiellement, il suffit de déplacer le répertoire de travail à un niveau supérieur (ou n'importe quel emplacement relatif), d'ajouter cela à votre chemin, puis de déplacer le répertoire de travail à l'endroit où il a commencé.

#to import from one level above:
cwd = os.getcwd()
os.chdir("..")
below_path =  os.getcwd()
sys.path.append(below_path)
os.chdir(cwd)
2
répondu Justin Muller 2012-01-27 17:43:59

vous pouvez simplement utiliser: from Desktop.filename import something

exemple:

étant donné que le fichier porte le nom test.py dans le répertoire Users/user/Desktop , et importera tout.

le code:

from Desktop.test import *

mais assurez-vous que vous faites un fichier vide appelé " __init__.py " dans ce répertoire

2
répondu 0x1996 2018-01-27 17:13:09

Je n'ai pas l'expérience de python, donc s'il y a quelque chose de mal dans mes mots, dites-le moi. Si votre hiérarchie de fichiers est organisée comme ceci:

project\
    module_1.py 
    module_2.py

module_1.py définit une fonction appelée func_1() , module_2.py :

from module_1 import func_1

def func_2():
    func_1()

if __name__ == '__main__':
    func_2()

et vous lancez python module_2.py dans cmd, il fera tourner ce que func_1() définit. C'est généralement comme ça qu'on importe les mêmes fichiers de hiérarchie. Mais quand vous écrivez from .module_1 import func_1 module_2.py , interprète python dira No module named '__main__.module_1'; '__main__' is not a package . Donc pour corriger cela, nous gardons juste le changement que nous faisons, et déplaçons les deux modules dans un paquet, et faisons un troisième module en tant qu'appelant pour lancer module_2.py .

project\
    package_1\
        module_1.py
        module_2.py
    main.py

main.py :

from package_1.module_2 import func_2

def func_3():
    func_2()

if __name__ == '__main__':
    func_3()

mais la raison pour laquelle nous ajoutons un . avant module_1 dans module_2.py est que si nous ne le faisons pas et que nous n'exécutons pas main.py , l'interpréteur python dira No module named 'module_1' , c'est un peu délicat, module_1.py est juste à côté de module_2.py . Maintenant je laisse func_1() dans module_1.py faire quelque chose:

def func_1():
    print(__name__)

ce __name__ enregistre qui appelle func_1. Maintenant, nous gardons le . avant module_1 , Lancez main.py , il affichera package_1.module_1 , pas module_1 . Il indique que celui qui appelle func_1() est dans la même hiérarchie que main.py , le . implique que module_1 est à la même hiérarchie que module_2.py lui-même. Donc, s'il n'y a pas de point, main.py reconnaîtra module_1 à la même hiérarchie qu'elle-même, elle peut reconnaître package_1 , mais pas ce que "sous" elle.

rendons ça un peu compliqué. Vous avez un config.ini et un module définit une fonction pour lire à la même hiérarchie que 'main.py'.

project\
    package_1\
        module_1.py
        module_2.py
    config.py
    config.ini
    main.py

et pour une raison inévitable, vous devez l'appeler avec module_2.py , elle doit donc être importée de la hiérarchie supérieure. module_2.py :

 import ..config
 pass

deux points signifie importation de la hiérarchie supérieure (trois points d'accès supérieur à Supérieur,et ainsi de suite). Maintenant on exécute main.py , l'interprète dira: ValueError:attempted relative import beyond top-level package . Le" paquet de haut niveau "ici est main.py . Juste parce que config.py est à côté de main.py , ils sont à la même hiérarchie, config.py n'est pas "sous" main.py , ou il n'est pas "dirigé" par main.py , donc c'est au-delà de main.py . Pour corriger cela, la manière la plus simple est:

project\
    package_1\
        module_1.py
        module_2.py
    config.py
    config.ini
main.py

je pense que c'est coïncider avec le principe d'organiser la hiérarchie de dossier de projet, vous devriez organiser des modules avec la fonction différente dans différents dossiers, et laissez juste un haut appelant à l'extérieur, et vous pouvez importer comment jamais vous voulez.

0
répondu OmouYue 2017-11-09 14:38:21

cela fonctionne aussi, et est beaucoup plus simple que n'importe quoi avec le sys module:

with open("C:/yourpath/foobar.py") as f:
    eval(f.read())
-1
répondu jgilley 2018-07-25 20:23:39

Appelez-moi excessivement prudent, mais j'aime rendre le mien plus portable parce qu'il est dangereux de supposer que les fichiers seront toujours au même endroit sur chaque ordinateur. Personnellement, j'ai le code pour rechercher le chemin du fichier en premier. J'utilise Linux pour que le mien ressemble à ceci:

import os, sys
from subprocess import Popen, PIPE
try:
    path = Popen("find / -name 'file' -type f", shell=True, stdout=PIPE).stdout.read().splitlines()[0]
    if not sys.path.__contains__(path):
        sys.path.append(path)
except IndexError:
    raise RuntimeError("You must have FILE to run this program!")

C'est bien sûr à moins que vous n'ayez l'intention de les emballer ensemble. Mais si c'est le cas, vous n'avez pas vraiment besoin de deux fichiers distincts de toute façon.

-14
répondu SuperFamousGuy 2017-08-28 14:04:45