Question

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 il s’agit d’une option de configuration.

Était-ce utile?

La solution

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 Python compilés et les DLL.

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

Autres conseils

L’avantage d’ajouter un chemin à sys.path (par rapport à imp), c’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

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 connaissiez 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

Il semble que vous ne souhaitiez pas importer spécifiquement le fichier de configuration (ce qui entraîne de nombreux effets secondaires et 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 +

Vous pouvez utiliser le

load_source(module_name, path_to_file) 

Méthode de module imp .

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. Le code suivant est requis dans Python 3.5+ (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" L'erreur "SystemError: Le module parent 'mymodule" n'est pas chargé et ne peut donc pas effectuer d'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 la suivante: si vous avez sys.modules ['spam'] et sys.modules ['spam.foo'] (comme vous le feriez après import), ces derniers doivent apparaître comme l'attribut foo de l'ancien " comme indiqué ici .

J'ai proposé une version légèrement modifiée de la merveilleuse réponse de SebastianRittau (pour Python > 3.4 je pense). , ce qui vous permettra de charger un fichier avec n'importe quelle extension en tant que module en utilisant spec_from_loader au lieu de emplacement_fichier_du_fichier_fichier :

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 une SourceFileLoader correspond au machines 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 emplacement_fichier_fichier_fichier sans spécifier le chargeur car .txt n'est pas dans importlib.machinery.SOURCE_SUFFIXES .

Voici un code qui fonctionne dans toutes les versions de Python, de la version 2.7 à la 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 jusqu’à présent le seul qui fonctionne dans toutes les versions.

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

Ajout de 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 , une autre question sur stackexchange

Voulez-vous dire charger ou importer?

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

/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
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')

Je pense 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 le faire:

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

... mais cela devrait faire le travail.

Cela devrait fonctionner

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)

Vous pouvez utiliser le module pkgutil (plus précisément le walk_packages ) pour obtenir une liste des packages dans le 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!

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

Ceci 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.

Je ne dis pas que c'est mieux, mais par souci d'exhaustivité, je voulais suggérer le exec , disponible en python 2 et 3. exec vous permet d'exécuter du code arbitraire dans l'étendue globale ou dans une étendue interne, fournie sous forme de dictionnaire.

Par exemple, si vous avez un module stocké dans " / chemin / vers / 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, tel que la possibilité de fournir des commandes intégrées personnalisées.

Et si le fait d’avoir accès via des attributs plutôt que des 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)

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

Créer un module python test.py

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

Créer un 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.

J'ai créé un package qui utilise imp pour vous. Je l'appelle fichier_importation 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 à l'adresse suivante:

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

ou à

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

Importer les 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)

Sous Linux, l’ajout d’un lien symbolique dans le répertoire dans lequel 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 *

moyen 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

Une solution simple utilisant importlib à la place du package imp (testé pour Python 2.7, bien que cela fonctionne également 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")

Vous pouvez maintenant utiliser directement 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 réel du module que nous souhaitons importer pour pouvoir l'utiliser dans notre code. Ceci est utile, par exemple. si le chemin du module est un argument configurable.

En ajoutant ceci à la liste des réponses car je n’ai rien trouvé qui puisse fonctionner. 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()

Cette réponse est un complément à la réponse de Sebastian Rittau répondant au commentaire: "mais que se passe-t-il si vous n'avez pas le nom du module?" C'est un moyen simple et rapide d'obtenir le nom du module python probable avec un nom de fichier: il monte simplement l'arborescence jusqu'à trouver un répertoire sans fichier __ init __. Py , puis le reconvertit en fichier. nom de fichier. Pour Python 3.4+ (utilise pathlib), ce qui est logique puisque les utilisateurs de Py2 peuvent utiliser "imp". ou d'autres façons 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 existe certainement des possibilités d’amélioration, et les fichiers facultatifs __ init __. py pourraient nécessiter d’autres modifications, mais si vous avez __ init __. py en général, c’est pratique. .

Je pense que le meilleur moyen est d'utiliser la documentation officielle ( 29.1. & # 8212; Accéder aux internes d'importation ):

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()
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top