web-dev-qa-db-fra.com

Comment importer un module avec le chemin complet?

Comment puis-je charger un module Python étant donné son chemin complet? Notez que le fichier peut être n'importe où dans le système de fichiers, car c'est une option de configuration.

966
derfred

Pour Python 3.5+, utilisez:

import importlib.util
spec = importlib.util.spec_from_file_location("module.name", "/path/to/file.py")
foo = importlib.util.module_from_spec(spec)
spec.loader.exec_module(foo)
foo.MyClass()

Pour Python 3.3 et 3.4, utilisez:

from importlib.machinery import SourceFileLoader

foo = SourceFileLoader("module.name", "/path/to/file.py").load_module()
foo.MyClass()

(Bien que cela soit déconseillé dans Python 3.4.)

Pour Python 2, utilisez:

import imp

foo = imp.load_source('module.name', '/path/to/file.py')
foo.MyClass()

Il existe des fonctions pratiques équivalentes pour les fichiers et les DLL compilés Python.

Voir aussi http://bugs.python.org/issue21436 .

1116
Sebastian Rittau

L’avantage d’ajouter un chemin à sys.path (plutôt que d’utiliser imp) est que cela simplifie les choses lors de l’importation de plusieurs modules à partir d’un seul paquet. Par exemple:

import sys
# the mock-0.3.1 dir contains testcase.py, testutils.py & mock.py
sys.path.append('/foo/bar/mock-0.3.1')

from testcase import TestCase
from testutils import RunTests
from mock import Mock, sentinel, patch
374
Daryl Spitzer

Il semble que vous ne souhaitiez pas importer spécifiquement le fichier de configuration (ce qui entraîne de nombreux effets secondaires et des complications supplémentaires), vous souhaitez simplement l'exécuter et pouvoir accéder à l'espace de noms obtenu. La bibliothèque standard fournit une API spécifiquement pour cela sous la forme de runpy.run_path :

from runpy import run_path
settings = run_path("/path/to/file.py")

Cette interface est disponible dans Python 2.7 et Python 3.2+

20
ncoghlan

Si votre module de niveau supérieur n'est pas un fichier mais est présenté sous la forme d'un répertoire avec __init__.py, la solution acceptée fonctionne presque, mais pas tout à fait. Dans Python 3.5+, le code suivant est requis (notez la ligne ajoutée qui commence par 'sys.modules'):

MODULE_PATH = "/path/to/your/module/__init__.py"
MODULE_NAME = "mymodule"
import importlib
import sys
spec = importlib.util.spec_from_file_location(MODULE_NAME, MODULE_PATH)
module = importlib.util.module_from_spec(spec)
sys.modules[spec.name] = module 
spec.loader.exec_module(module)

Sans cette ligne, lorsque exec_module est exécuté, il tente de lier les importations relatives de votre niveau supérieur __init__.py au nom du module de niveau supérieur - dans ce cas, "mymodule". Mais "mymodule" n'est pas encore chargé et vous obtiendrez l'erreur "SystemError: le module parent 'mymodule' n'est pas chargé, impossible d'effectuer une importation relative". Vous devez donc lier le nom avant de le charger. La raison en est l’invariant fondamental du système d’importation relatif: "La détention invariante est que si vous avez sys.modules ['spam'] et sys.modules ['spam.foo'] (comme vous le feriez après l’importation ci-dessus ), le dernier doit apparaître comme l'attribut foo de l'ancien " comme discuté ici .

20
Sam Grondahl

Pour importer votre module, vous devez ajouter son répertoire à la variable d'environnement, de manière temporaire ou permanente.

Temporairement

import sys
sys.path.append("/path/to/my/modules/")
import my_module

En permanence

Ajoutez la ligne suivante à votre fichier .bashrc (sous Linux) et exécutez source ~/.bashrc dans le terminal:

export PYTHONPATH="${PYTHONPATH}:/path/to/my/modules/"

Crédit/Source: saarrrr , autre question de stackexchange

19
Miladiouss

Vous pouvez également faire quelque chose comme ceci et ajouter le répertoire dans lequel se trouve le fichier de configuration au chemin de chargement Python, puis effectuer une importation normale en supposant que vous connaissez le nom du fichier à l'avance. cette affaire "config".

En désordre, mais ça marche.

configfile = '~/config.py'

import os
import sys

sys.path.append(os.path.dirname(os.path.expanduser(configfile)))

import config
19
ctcherry

Vous pouvez utiliser le

load_source(module_name, path_to_file) 

méthode de module imp .

17
zuber

Je suis arrivé avec une version légèrement modifiée de réponse merveilleuse de @ SebastianRitta (pour Python> 3.4 je pense), qui vous permettra de charger un fichier avec n'importe quelle extension en tant que module en utilisant spec_from_loader au lieu de spec_from_file_location :

_from importlib.util import spec_from_loader, module_from_spec
from importlib.machinery import SourceFileLoader 

spec = spec_from_loader("module.name", SourceFileLoader("module.name", "/path/to/file.py"))
mod = module_from_spec(spec)
spec.loader.exec_module(mod)
_

L'avantage d'encoder le chemin dans un SourceFileLoader explicite est que le machinerie n'essaiera pas de déterminer le type du fichier à partir de l'extension. Cela signifie que vous pouvez charger quelque chose comme un fichier _.txt_ en utilisant cette méthode, mais vous ne pouvez pas le faire avec _spec_from_file_location_ sans spécifier le chargeur car _.txt_ n'est pas dans importlib.machinery.SOURCE_SUFFIXES .

13
Mad Physicist

Voulez-vous dire charger ou importer?

Vous pouvez manipuler la liste sys.path pour spécifier le chemin d'accès à votre module, puis importer votre module. Par exemple, donné un module à:

/foo/bar.py

Vous pourriez faire:

import sys
sys.path[0:0] = ['/foo'] # puts the /foo directory at the start of your path
import bar
12
Wheat

Voici un code qui fonctionne dans toutes les versions de Python, de 2.7 à 3.5 et probablement même d’autres.

config_file = "/tmp/config.py"
with open(config_file) as f:
    code = compile(f.read(), config_file, 'exec')
    exec(code, globals(), locals())

Je l'ai testé. C'est peut-être moche mais c'est le seul qui fonctionne jusqu'à présent dans toutes les versions.

12
sorin
def import_file(full_path_to_module):
    try:
        import os
        module_dir, module_file = os.path.split(full_path_to_module)
        module_name, module_ext = os.path.splitext(module_file)
        save_cwd = os.getcwd()
        os.chdir(module_dir)
        module_obj = __import__(module_name)
        module_obj.__file__ = full_path_to_module
        globals()[module_name] = module_obj
        os.chdir(save_cwd)
    except:
        raise ImportError

import_file('/home/somebody/somemodule.py')
10
Chris Calloway

Je crois que vous pouvez utiliser imp.find_module() et imp.load_module() pour charger le module spécifié. Vous devez séparer le nom du module du chemin, c'est-à-dire que si vous voulez charger /home/mypath/mymodule.py, vous devez effectuer les tâches suivantes:

imp.find_module('mymodule', '/home/mypath/')

... mais cela devrait faire le travail.

8
Matt

Créer le module python test.py

import sys
sys.path.append("<project-path>/lib/")
from tes1 import Client1
from tes2 import Client2
import tes3

Créez le module python test_check.py

from test import Client1
from test import Client2
from test import test3

Nous pouvons importer le module importé à partir du module.

4
abhimanyu

Vous pouvez utiliser le module pkgutil (en particulier la méthode walk_packages ) pour obtenir la liste des packages du répertoire en cours. À partir de là, il est facile d’utiliser la machine importlib pour importer les modules souhaités:

_import pkgutil
import importlib

packages = pkgutil.walk_packages(path='.')
for importer, name, is_package in packages:
    mod = importlib.import_module(name)
    # do whatever you want with module now, it's been imported!
_
3
bob_twinkles

Cela devrait marcher

path = os.path.join('./path/to/folder/with/py/files', '*.py')
for infile in glob.glob(path):
    basename = os.path.basename(infile)
    basename_without_extension = basename[:-3]

    # http://docs.python.org/library/imp.html?highlight=imp#module-imp
    imp.load_source(basename_without_extension, infile)
3
Hengjie

Je ne dis pas que c'est mieux, mais par souci d'exhaustivité, je voulais suggérer la fonction exec , disponible à la fois dans python 2 et 3. exec vous permet de exécuter du code arbitraire soit dans la portée globale, soit dans une portée interne, fournie sous forme de dictionnaire.

Par exemple, si vous avez un module stocké dans "/path/to/module "avec la fonction foo(), vous pouvez l'exécuter en procédant comme suit:

module = dict()
with open("/path/to/module") as f:
    exec(f.read(), module)
module['foo']()

Cela rend un peu plus explicite le fait que vous chargiez le code de manière dynamique et vous donne un pouvoir supplémentaire, comme la possibilité de fournir des commandes intégrées personnalisées.

Et si le fait d’avoir accès par le biais d’attributs plutôt que de clés est important, vous pouvez concevoir une classe dict personnalisée pour les globals, qui fournit cet accès, par exemple:

class MyModuleClass(dict):
    def __getattr__(self, name):
        return self.__getitem__(name)
3
yoniLavi

Cette zone de Python 3.4 semble extrêmement difficile à comprendre! Cependant, avec un peu de piratage informatique utilisant le code de Chris Calloway au début, j'ai réussi à faire fonctionner quelque chose. Voici la fonction de base.

def import_module_from_file(full_path_to_module):
    """
    Import a module given the full path/filename of the .py file

    Python 3.4

    """

    module = None

    try:

        # Get module name and path from full path
        module_dir, module_file = os.path.split(full_path_to_module)
        module_name, module_ext = os.path.splitext(module_file)

        # Get module "spec" from filename
        spec = importlib.util.spec_from_file_location(module_name,full_path_to_module)

        module = spec.loader.load_module()

    except Exception as ec:
        # Simple error printing
        # Insert "sophisticated" stuff here
        print(ec)

    finally:
        return module

Cela semble utiliser des modules non obsolètes de Python 3.4. Je ne prétends pas comprendre pourquoi, mais cela semble fonctionner dans le cadre d'un programme. J'ai trouvé que la solution de Chris fonctionnait sur la ligne de commande mais pas à l'intérieur d'un programme.

3
Redlegjed

Pour importer un module à partir d'un nom de fichier donné, vous pouvez prolonger temporairement le chemin et restaurer le chemin système dans le bloc finally reference:

filename = "directory/module.py"

directory, module_name = os.path.split(filename)
module_name = os.path.splitext(module_name)[0]

path = list(sys.path)
sys.path.insert(0, directory)
try:
    module = __import__(module_name)
finally:
    sys.path[:] = path # restore
3
Peter Zhu

Importer des modules de package à l'exécution (recette Python)

http://code.activestate.com/recipes/223972/

###################
##                #
## classloader.py #
##                #
###################

import sys, types

def _get_mod(modulePath):
    try:
        aMod = sys.modules[modulePath]
        if not isinstance(aMod, types.ModuleType):
            raise KeyError
    except KeyError:
        # The last [''] is very important!
        aMod = __import__(modulePath, globals(), locals(), [''])
        sys.modules[modulePath] = aMod
    return aMod

def _get_func(fullFuncName):
    """Retrieve a function object from a full dotted-package name."""

    # Parse out the path, module, and function
    lastDot = fullFuncName.rfind(u".")
    funcName = fullFuncName[lastDot + 1:]
    modPath = fullFuncName[:lastDot]

    aMod = _get_mod(modPath)
    aFunc = getattr(aMod, funcName)

    # Assert that the function is a *callable* attribute.
    assert callable(aFunc), u"%s is not callable." % fullFuncName

    # Return a reference to the function itself,
    # not the results of the function.
    return aFunc

def _get_class(fullClassName, parentClass=None):
    """Load a module and retrieve a class (NOT an instance).

    If the parentClass is supplied, className must be of parentClass
    or a subclass of parentClass (or None is returned).
    """
    aClass = _get_func(fullClassName)

    # Assert that the class is a subclass of parentClass.
    if parentClass is not None:
        if not issubclass(aClass, parentClass):
            raise TypeError(u"%s is not a subclass of %s" %
                            (fullClassName, parentClass))

    # Return a reference to the class itself, not an instantiated object.
    return aClass


######################
##       Usage      ##
######################

class StorageManager: pass
class StorageManagerMySQL(StorageManager): pass

def storage_object(aFullClassName, allOptions={}):
    aStoreClass = _get_class(aFullClassName, StorageManager)
    return aStoreClass(allOptions)
2
user10370

Sous Linux, l’ajout d’un lien symbolique dans le répertoire où se trouve votre script python fonctionne.

c'est à dire:

ln -s /absolute/path/to/module/module.py /absolute/path/to/script/module.py

python créera /absolute/path/to/script/module.pyc et le mettra à jour si vous modifiez le contenu de /absolute/path/to/module/module.py

puis inclure les éléments suivants dans mypythonscript.py

from module import *
2
user2760152

J'ai créé un package qui utilise imp pour vous. Je l'appelle import_file et voici comment il est utilisé:

>>>from import_file import import_file
>>>mylib = import_file('c:\\mylib.py')
>>>another = import_file('relative_subdir/another.py')

Vous pouvez l'obtenir à:

http://pypi.python.org/pypi/import_file

ou à

http://code.google.com/p/import-file/

2
ubershmekel

manière assez simple: supposons que vous vouliez importer un fichier avec un chemin relatif ../../MyLibs/pyfunc.py


libPath = '../../MyLibs'
import sys
if not libPath in sys.path: sys.path.append(libPath)
import pyfunc as pf

Mais si vous le faites sans garde, vous pouvez enfin avoir un très long chemin

1
Andrei Keino

Une solution simple utilisant importlib à la place du package imp (testé pour Python 2.7, bien que cela devrait également fonctionner pour Python 3):

import importlib

dirname, basename = os.path.split(pyfilepath) # pyfilepath: '/my/path/mymodule.py'
sys.path.append(dirname) # only directories should be added to PYTHONPATH
module_name = os.path.splitext(basename)[0] # '/my/path/mymodule.py' --> 'mymodule'
module = importlib.import_module(module_name) # name space of defined module (otherwise we would literally look for "module_name")

Maintenant, vous pouvez directement utiliser l'espace de noms du module importé, comme ceci:

a = module.myvar
b = module.myfunc(a)

L’avantage de cette solution est que nous n’avons même pas besoin de connaître le nom du module à importer, pour pouvoir l’utiliser dans notre code. Ceci est utile, par exemple. dans le cas où le chemin du module est un argument configurable.

1
Ataxias

Ajouter ceci à la liste des réponses car je ne trouvais rien qui puisse fonctionner. Ceci autorisera les importations de modules compilés (pyd) python dans 3.4:

import sys
import importlib.machinery

def load_module(name, filename):
    # If the Loader finds the module name in this list it will use
    # module_name.__file__ instead so we need to delete it here
    if name in sys.modules:
        del sys.modules[name]
    loader = importlib.machinery.ExtensionFileLoader(name, filename)
    module = loader.load_module()
    locals()[name] = module
    globals()[name] = module

load_module('something', r'C:\Path\To\something.pyd')
something.do_something()
0
David

Cette réponse est un complément à la réponse de Sebastian Rittau répondant au commentaire: "mais si vous n'avez pas le nom du module?" C'est un moyen simple et rapide d'obtenir le nom probable du module python avec un nom de fichier - il ne fait que remonter dans l'arborescence jusqu'à ce qu'il trouve un répertoire sans fichier ___init__.py_ puis le reconvertit en un nom de fichier. Pour Python 3.4+ (utilise pathlib), ce qui est logique depuis que les utilisateurs de Py2 peuvent utiliser "imp" ou d'autres méthodes pour importer des importations relatives:

_import pathlib

def likely_python_module(filename):
    '''
    Given a filename or Path, return the "likely" python module name.  That is, iterate
    the parent directories until it doesn't contain an __init__.py file.

    :rtype: str
    '''
    p = pathlib.Path(filename).resolve()
    paths = []
    if p.name != '__init__.py':
        paths.append(p.stem)
    while True:
        p = p.parent
        if not p:
            break
        if not p.is_dir():
            break

        inits = [f for f in p.iterdir() if f.name == '__init__.py']
        if not inits:
            break

        paths.append(p.stem)

    return '.'.join(reversed(paths))
_

Il existe certainement des possibilités d’amélioration, et les fichiers optionnels ___init__.py_ peuvent nécessiter d’autres modifications, mais si vous avez ___init__.py_ en général, c’est tout.

0