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.
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 .
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
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+
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 .
Pour importer votre module, vous devez ajouter son répertoire à la variable d'environnement, de manière temporaire ou permanente.
import sys
sys.path.append("/path/to/my/modules/")
import my_module
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
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
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
.
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
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.
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 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.
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.
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!
_
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)
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)
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.
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
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)
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 *
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 à
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
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.
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()
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.