Comment importer un module avec le chemin complet?

Comment puis-je charger un module Python avec son chemin complet? Notez que le fichier peut être n'importe où dans le système de fichiers, car il s'agit d'une option de configuration.

808
demandé sur ferkulat 2008-09-16 02:30:55

24 réponses

pour Python 3.5 + utiliser:

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 Utilisation:

from importlib.machinery import SourceFileLoader

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

(bien que cela ait été déprécié dans Python 3.4.)

Python 2:

import imp

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

il existe des fonctions équivalentes de commodité pour les fichiers Python et DLLs compilés.

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

926
répondu Sebastian Rittau 2015-12-07 14:31:23

l'avantage d'ajouter un chemin à sys.path (over using imp) est qu'il simplifie les choses lors de l'importation de plus d'un module à 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
324
répondu Daryl Spitzer 2008-09-24 19:36:16

vous pouvez aussi faire quelque chose comme ceci et ajouter le répertoire dans lequel le fichier de configuration est placé au chemin de chargement Python, et ensuite juste faire une importation normale, en supposant que vous connaissez le nom du fichier à l'avance, dans ce cas"config".

Messy, mais ça marche.

configfile = '~/config.py'

import os
import sys

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

import config
19
répondu ctcherry 2014-01-17 22:38:07

vous pouvez utiliser le

load_source(module_name, path_to_file) 

méthode de module imp .

16
répondu zuber 2014-11-11 07:07:34

il semble que vous ne voulez pas importer spécifiquement le fichier de configuration (qui a beaucoup d'effets secondaires et des complications supplémentaires impliqués), vous voulez juste l'exécuter, et être en mesure d'accéder à l'espace de noms résultant. La bibliothèque standard fournit une API spécifique sous la forme de runpy.run_path :

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

cette interface est disponible en python 2.7 et Python 3.2 +

14
répondu ncoghlan 2016-05-20 06:52:17
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
répondu Chris Calloway 2008-09-16 01:43:04

voulez-vous dire chargement ou importation?

vous pouvez manipuler le système.liste de chemin spécifiez le chemin vers votre module, puis importez votre module. Par exemple, avec un module à:

/foo/bar.py

Vous pouvez faire:

import sys
sys.path[0:0] = '/foo' # puts the /foo directory at the start of your path
import bar
9
répondu Wheat 2010-07-09 05:30:00

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.-à-d. Si vous voulez charger /home/mypath/mymodule.py vous devez faire:

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

...mais que doit faire le travail.

8
répondu Matt 2015-01-02 11:08:38

voici un code qui fonctionne dans toutes les versions de Python, à partir 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é. Il peut être laid, mais jusqu'à présent est le seul qui fonctionne dans toutes les versions.

7
répondu sorin 2016-06-03 10:04:52

j'ai trouvé une version légèrement modifiée de @Sebastianrittau's wonderful answer (pour Python > 3.4 je pense), qui vous permettra de charger un fichier avec n'importe quelle extension comme 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 explicite SourceFileLoader est que le machine n'essaiera pas de comprendre 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 parce que .txt n'est pas importlib.machinery.SOURCE_SUFFIXES .

6
répondu Mad Physicist 2018-09-19 18:13:16

si votre module supérieur n'est pas un fichier mais est empaqueté comme un répertoire avec _ _ init__.py, puis la solution acceptée fonctionne presque, mais pas tout à fait. En Python 3.5+ le code suivant est nécessaire (notez la ligne ajoutée qui commence par 'sys.modules'):

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

sans cette ligne, quand exec_module est exécuté, il essaie de lier les importations relatives dans votre niveau supérieur __init__.py au niveau supérieur nom du module -- dans ce cas"mymodule". Mais "mymodule" n'est pas chargé cependant, vous obtiendrez l'erreur "SystemError: le module Parent 'mymodule' n'est pas chargé, ne peut pas effectuer l'importation relative". Donc vous devez lier le nom avant de le charger. La raison en est l'invariant fondamental du système d'importation relatif: "le maintien invariant est que si vous avez sys.modules ['spam'] et sys.les modules de['spam.foo'] (comme vous le feriez après l'importation ci-dessus), ce dernier doit apparaître comme l'attribut foo du premier tel que discuté ici .

5
répondu Sam Grondahl 2018-05-17 15:23:41

ça 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
répondu Hengjie 2012-01-04 04:28:50

ce domaine de Python 3.4 semble extrêmement tortueux à comprendre! Cependant, avec un peu de piratage utilisant le code de Chris Calloway comme point de départ, 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

ceci semble utiliser des modules non-dépréciés de Python 3.4. Je ne prétends pas comprendre pourquoi, mais il semble fonctionner à partir 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
répondu Redlegjed 2015-04-12 12:22:56

je ne dis pas que c'est mieux, mais par souci d'exhaustivité, je voulais suggérer la exec fonction, disponible en python 2 et 3. exec permet d'exécuter du code arbitraire dans le contexte global, ou dans une portée interne, à condition qu'un dictionnaire.

par exemple, si vous avez un module stocké dans "/path/to/module "avec la fonction foo() , vous pouvez l'exécuter en faisant ce qui suit:

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

cela rend un peu plus explicite que vous chargez du code dynamiquement, et vous accorde une certaine puissance supplémentaire, comme la possibilité de fournir des builtins personnalisés.

et si avoir accès par attributs, au lieu de clés est important pour vous, vous pouvez concevoir une classe dict personnalisée pour les globals, qui fournit un tel accès, par exemple:

class MyModuleClass(dict):
    def __getattr__(self, name):
        return self.__getitem__(name)
3
répondu yoniLavi 2015-06-02 19:57:46

pour importer un module à partir d'un nom de fichier donné, vous pouvez étendre temporairement le chemin, et restaurer le chemin du système dans le bloc final référence:

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
répondu Peter Zhu 2015-10-02 11:14:13

Importer un package modules au moment de l'exécution (Python recette)

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
répondu user10370 2013-12-22 02:17:57

vous pouvez utiliser le module pkgutil (spécifiquement la méthode walk_packages ) pour obtenir une liste des paquets dans le répertoire courant. De là, il est trivial d'utiliser la machine importlib pour importer les modules que vous voulez:

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!
2
répondu bob_twinkles 2015-01-02 11:04:17

sous Linux, ajouter un lien symbolique dans le répertoire où votre script python se trouve 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 changez le contenu de /absolute/path/to/module/module.py

alors inclure ce qui suit dans mypythonscript.py

from module import *
2
répondu user2760152 2018-04-11 17:21:07

j'ai fait un paquet 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 /

1
répondu ubershmekel 2011-06-08 19:41:29

très simple: supposons que vous voulez importer le fichier avec le 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 obtenir un très long chemin""

1
répondu Andrei Keino 2018-01-26 04:52:15

une solution simple utilisant importlib au lieu du paquet imp (testé pour Python 2.7, bien qu'il devrait fonctionner pour Python 3 aussi):

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 utiliser directement l'espace de nom 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, nous voudrions importer , afin de l'utiliser dans notre code. Ce est utile, par exemple dans le cas où le chemin du module est un argument configurable.

1
répondu Ataxias 2018-07-28 02:24:45

ajoutant ceci à la liste de réponses car je n'ai rien trouvé qui ait fonctionné. Cela permettra l'importation de modules Python compilés (pyd) en 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
répondu David 2018-01-10 15:58:46

cette réponse est un supplément à la réponse de Sebastian Rittau répondant au commentaire: "mais que faire si vous n'avez pas le nom du module?"C'est une façon rapide et sale d'obtenir le nom probable d'un module python donné à un nom de fichier -- il va juste en haut de l'arbre jusqu'à ce qu'il trouve un répertoire sans fichier __init__.py et le transforme à nouveau en un nom de fichier. Pour Python 3.4+ (utilise pathlib), ce qui a du sens puisque les gens de Py2 peuvent utiliser "imp" ou d'autres moyens de faire 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 y a certainement des possibilités d'amélioration, et les fichiers optionnels __init__.py pourraient nécessiter d'autres modifications, mais si vous avez __init__.py en général, cela fait l'affaire.

0
répondu Michael Scott Cuthbert 2018-09-08 15:29:30

la meilleure façon, je pense, est de la documentation officielle ( 29.1. imp - l'Accès à l'importation internals ):

import imp
import sys

def __import__(name, globals=None, locals=None, fromlist=None):
    # Fast path: see if the module has already been imported.
    try:
        return sys.modules[name]
    except KeyError:
        pass

    # If any of the following calls raises an exception,
    # there's a problem we can't handle -- let the caller handle it.

    fp, pathname, description = imp.find_module(name)

    try:
        return imp.load_module(name, fp, pathname, description)
    finally:
        # Since we may exit via an exception, close fp explicitly.
        if fp:
            fp.close()
-1
répondu Zompa 2014-11-25 12:58:47