Comment puis-je charger un module Python compte tenu de son chemin complet? Notez que le fichier peut se trouver n'importe où dans le système de fichiers, car il s'agit d'une option de configuration.
Comment puis-je charger un module Python compte tenu de son chemin complet? Notez que le fichier peut se trouver n'importe où dans le système de fichiers, car il s'agit d'une option de configuration.
Réponses:
Pour l'utilisation de Python 3.5+:
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 obsolète 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 de commodité équivalentes pour les fichiers et DLL Python compilés.
Voir également http://bugs.python.org/issue21436 .
__import__
.
imp.load_source
définit uniquement .__name__
le module retourné. cela n'affecte pas le chargement.
imp.load_source()
détermine la clé de la nouvelle entrée créée dans le sys.modules
dictionnaire, donc le premier argument affecte effectivement le chargement.
imp
module est obsolète depuis la version 3.4: Le imp
package est en attente de dépréciation en faveur de importlib
.
L'avantage d'ajouter un chemin d'accès à sys.path (au lieu d'utiliser imp) est qu'il simplifie les choses lors de l'importation de plusieurs modules à partir d'un même package. 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
sys.path.append
pour pointer vers un seul fichier python au lieu d'un répertoire?
importlib.import_module(mod_name)
peut être utilisé à la place de l'importation explicite ici si le nom du module n'est pas connu au moment de l'exécution, j'ajouterais un sys.path.pop()
à la fin, cependant, en supposant que le code importé n'essaye pas d'importer plus de modules tel qu'il est utilisé.
Si votre module de niveau supérieur n'est pas un fichier mais est empaqueté comme un répertoire avec __init__.py, alors la solution acceptée fonctionne presque, mais pas tout à fait. Dans 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"
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 essaie 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é, vous obtiendrez donc l'erreur "SystemError: le module parent 'mymodule' n'est pas chargé, ne peut 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 position invariante est que si vous avez sys.modules ['spam'] et sys.modules ['spam.foo'] (comme vous le feriez après l'importation ci-dessus ), ce dernier doit apparaître comme l'attribut foo du premier ", comme expliqué ici .
mymodule
?
/path/to/your/module/
c'est en fait /path/to/your/PACKAGE/
? et mymodule
tu veux dire myfile.py
?
Pour importer votre module, vous devez ajouter son répertoire à la variable d'environnement, temporairement ou définitivement.
import sys
sys.path.append("/path/to/my/modules/")
import my_module
Ajout de la ligne suivante à votre .bashrc
fichier (sous linux) et exécution source ~/.bashrc
dans le terminal:
export PYTHONPATH="${PYTHONPATH}:/path/to/my/modules/"
Crédit / Source: saarrrr , une autre question d'échange de pile
Il semble que vous ne souhaitiez pas importer spécifiquement le fichier de configuration (qui comporte de nombreux effets secondaires et complications supplémentaires), vous voulez simplement l'exécuter et pouvoir accéder à l'espace de noms résultant. 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+
result[name]
, result.get('name', default_value)
, etc.)
from runpy import run_path; from argparse import Namespace; mod = Namespace(**run_path('path/to/file.py'))
Vous pouvez également faire quelque chose comme ça et ajouter le répertoire dans lequel se trouve le fichier de configuration dans le chemin de chargement Python, puis faire juste une importation normale, en supposant que vous connaissez le nom du fichier à l'avance, dans ce cas "config".
Désordonné, mais cela fonctionne.
configfile = '~/config.py'
import os
import sys
sys.path.append(os.path.dirname(os.path.expanduser(configfile)))
import config
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')
except:
clause fourre-tout est rarement une bonne idée.
save_cwd = os.getcwd()
try: …
finally: os.chdir(save_cwd)
this is already addressed by the standard library
oui, mais python a la mauvaise habitude de ne pas être rétrocompatible ... comme la réponse vérifiée dit qu'il y a 2 façons différentes avant et après 3.3. Dans ce cas, je préfère écrire ma propre fonction universelle que de vérifier la version à la volée. Et oui, peut-être que ce code n'est pas trop bien protégé contre les erreurs, mais il montre une idée (qui est os.chdir (), je n'y ai pas pensé), sur la base de laquelle je peux écrire un meilleur code. D'où +1.
Voici du 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 jusqu'à présent c'est le seul qui fonctionne dans toutes les versions.
load_source
ne l'a pas fait car elle importe le script et fournit l'accès au script aux modules et aux globaux au moment de l'importation.
J'ai trouvé une version légèrement modifiée de la merveilleuse réponse de @ SebastianRittau (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 de manière explicite SourceFileLoader
est que la machine n'essaiera pas de comprendre le type du fichier à partir de l'extension. Cela signifie que vous pouvez charger quelque chose comme un .txt
fichier à l'aide de cette méthode, mais vous ne pouvez pas le faire spec_from_file_location
sans spécifier le chargeur car il .txt
n'est pas dans importlib.machinery.SOURCE_SUFFIXES
.
Voulez-vous dire charger ou importer?
Vous pouvez manipuler la sys.path
liste, spécifier le chemin d'accès à votre module, puis importer votre module. Par exemple, étant 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
sys.path[0:0] = ['/foo']
Explicit is better than implicit.
Alors pourquoi pas à la sys.path.insert(0, ...)
place de sys.path[0:0]
?
Je pense que vous pouvez utiliser imp.find_module()
et imp.load_module()
charger le module spécifié. Vous devrez séparer le nom du module du chemin d'accès, c'est-à-dire que si vous souhaitez charger, /home/mypath/mymodule.py
vous devrez faire:
imp.find_module('mymodule', '/home/mypath/')
... mais cela devrait faire le travail.
Vous pouvez utiliser le pkgutil
module (en particulier la walk_packages
méthode) pour obtenir une liste des packages dans le répertoire courant. De là, il est trivial d'utiliser la importlib
machinerie pour importer les modules que vous souhaitez:
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!
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éer le module python test_check.py
from test import Client1
from test import Client2
from test import test3
Nous pouvons importer le module importé depuis le module.
Cette zone de Python 3.4 semble être extrêmement tortueuse à comprendre! Cependant, avec un peu de piratage en utilisant le code de Chris Calloway pour commencer, 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 à partir d'un programme. J'ai trouvé que la solution de Chris fonctionnait sur la ligne de commande mais pas depuis l'intérieur d'un programme.
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
vous permet d'exécuter du code arbitraire dans la portée globale ou dans une portée interne, fourni 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 chargement dynamique du code et vous accorde une puissance supplémentaire, telle que la possibilité de fournir des fonctions intégrées.
Et si avoir accès via des attributs, au lieu de clés est important pour vous, vous pouvez concevoir une classe de dict personnalisée pour les globaux, qui fournit un tel 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 temporairement étendre le chemin d'accès et restaurer le chemin d'accès système dans la référence de bloc finalement :
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
Si nous avons des scripts dans le même projet mais dans des répertoires différents, nous pouvons résoudre ce problème par la méthode suivante.
Dans cette situation , utils.py
est ensrc/main/util/
import sys
sys.path.append('./')
import src.main.util.utils
#or
from src.main.util.utils import json_converter # json_converter is example method
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)
name, ext = os.path.splitext(os.path.basename(infile))
. Votre méthode fonctionne car la restriction précédente à l'extension .py. En outre, vous devriez probablement importer le module dans une entrée de variable / dictionnaire.
J'ai fait 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 à
Importer des modules de package lors de 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
incluez ensuite les éléments suivants dans mypythonscript.py
from module import *
git
et en vérifiant votre git status
pour vérifier que vos modifications apportées au script sont effectivement en train de revenir au document source et ne se perdent pas dans l'éther.
J'ai écrit ma propre fonction d'importation globale et portable, basée sur le importlib
module, pour:
sys.path
ou sur un stockage de chemin de recherche.Les exemples de structure de répertoires:
<root>
|
+- test.py
|
+- testlib.py
|
+- /std1
| |
| +- testlib.std1.py
|
+- /std2
| |
| +- testlib.std2.py
|
+- /std3
|
+- testlib.std3.py
Dépendance et ordre d'inclusion:
test.py
-> testlib.py
-> testlib.std1.py
-> testlib.std2.py
-> testlib.std3.py
La mise en oeuvre:
Dernier magasin de modifications: https://sourceforge.net/p/tacklelib/tacklelib/HEAD/tree/trunk/python/tacklelib/tacklelib.py
test.py :
import os, sys, inspect, copy
SOURCE_FILE = os.path.abspath(inspect.getsourcefile(lambda:0)).replace('\\','/')
SOURCE_DIR = os.path.dirname(SOURCE_FILE)
print("test::SOURCE_FILE: ", SOURCE_FILE)
# portable import to the global space
sys.path.append(TACKLELIB_ROOT) # TACKLELIB_ROOT - path to the library directory
import tacklelib as tkl
tkl.tkl_init(tkl)
# cleanup
del tkl # must be instead of `tkl = None`, otherwise the variable would be still persist
sys.path.pop()
tkl_import_module(SOURCE_DIR, 'testlib.py')
print(globals().keys())
testlib.base_test()
testlib.testlib_std1.std1_test()
testlib.testlib_std1.testlib_std2.std2_test()
#testlib.testlib.std3.std3_test() # does not reachable directly ...
getattr(globals()['testlib'], 'testlib.std3').std3_test() # ... but reachable through the `globals` + `getattr`
tkl_import_module(SOURCE_DIR, 'testlib.py', '.')
print(globals().keys())
base_test()
testlib_std1.std1_test()
testlib_std1.testlib_std2.std2_test()
#testlib.std3.std3_test() # does not reachable directly ...
globals()['testlib.std3'].std3_test() # ... but reachable through the `globals` + `getattr`
testlib.py :
# optional for 3.4.x and higher
#import os, inspect
#
#SOURCE_FILE = os.path.abspath(inspect.getsourcefile(lambda:0)).replace('\\','/')
#SOURCE_DIR = os.path.dirname(SOURCE_FILE)
print("1 testlib::SOURCE_FILE: ", SOURCE_FILE)
tkl_import_module(SOURCE_DIR + '/std1', 'testlib.std1.py', 'testlib_std1')
# SOURCE_DIR is restored here
print("2 testlib::SOURCE_FILE: ", SOURCE_FILE)
tkl_import_module(SOURCE_DIR + '/std3', 'testlib.std3.py')
print("3 testlib::SOURCE_FILE: ", SOURCE_FILE)
def base_test():
print('base_test')
testlib.std1.py :
# optional for 3.4.x and higher
#import os, inspect
#
#SOURCE_FILE = os.path.abspath(inspect.getsourcefile(lambda:0)).replace('\\','/')
#SOURCE_DIR = os.path.dirname(SOURCE_FILE)
print("testlib.std1::SOURCE_FILE: ", SOURCE_FILE)
tkl_import_module(SOURCE_DIR + '/../std2', 'testlib.std2.py', 'testlib_std2')
def std1_test():
print('std1_test')
testlib.std2.py :
# optional for 3.4.x and higher
#import os, inspect
#
#SOURCE_FILE = os.path.abspath(inspect.getsourcefile(lambda:0)).replace('\\','/')
#SOURCE_DIR = os.path.dirname(SOURCE_FILE)
print("testlib.std2::SOURCE_FILE: ", SOURCE_FILE)
def std2_test():
print('std2_test')
testlib.std3.py :
# optional for 3.4.x and higher
#import os, inspect
#
#SOURCE_FILE = os.path.abspath(inspect.getsourcefile(lambda:0)).replace('\\','/')
#SOURCE_DIR = os.path.dirname(SOURCE_FILE)
print("testlib.std3::SOURCE_FILE: ", SOURCE_FILE)
def std3_test():
print('std3_test')
Sortie ( 3.7.4
):
test::SOURCE_FILE: <root>/test01/test.py
import : <root>/test01/testlib.py as testlib -> []
1 testlib::SOURCE_FILE: <root>/test01/testlib.py
import : <root>/test01/std1/testlib.std1.py as testlib_std1 -> ['testlib']
import : <root>/test01/std1/../std2/testlib.std2.py as testlib_std2 -> ['testlib', 'testlib_std1']
testlib.std2::SOURCE_FILE: <root>/test01/std1/../std2/testlib.std2.py
2 testlib::SOURCE_FILE: <root>/test01/testlib.py
import : <root>/test01/std3/testlib.std3.py as testlib.std3 -> ['testlib']
testlib.std3::SOURCE_FILE: <root>/test01/std3/testlib.std3.py
3 testlib::SOURCE_FILE: <root>/test01/testlib.py
dict_keys(['__name__', '__doc__', '__package__', '__loader__', '__spec__', '__annotations__', '__builtins__', '__file__', '__cached__', 'os', 'sys', 'inspect', 'copy', 'SOURCE_FILE', 'SOURCE_DIR', 'TackleGlobalImportModuleState', 'tkl_membercopy', 'tkl_merge_module', 'tkl_get_parent_imported_module_state', 'tkl_declare_global', 'tkl_import_module', 'TackleSourceModuleState', 'tkl_source_module', 'TackleLocalImportModuleState', 'testlib'])
base_test
std1_test
std2_test
std3_test
import : <root>/test01/testlib.py as . -> []
1 testlib::SOURCE_FILE: <root>/test01/testlib.py
import : <root>/test01/std1/testlib.std1.py as testlib_std1 -> ['testlib']
import : <root>/test01/std1/../std2/testlib.std2.py as testlib_std2 -> ['testlib', 'testlib_std1']
testlib.std2::SOURCE_FILE: <root>/test01/std1/../std2/testlib.std2.py
2 testlib::SOURCE_FILE: <root>/test01/testlib.py
import : <root>/test01/std3/testlib.std3.py as testlib.std3 -> ['testlib']
testlib.std3::SOURCE_FILE: <root>/test01/std3/testlib.std3.py
3 testlib::SOURCE_FILE: <root>/test01/testlib.py
dict_keys(['__name__', '__doc__', '__package__', '__loader__', '__spec__', '__annotations__', '__builtins__', '__file__', '__cached__', 'os', 'sys', 'inspect', 'copy', 'SOURCE_FILE', 'SOURCE_DIR', 'TackleGlobalImportModuleState', 'tkl_membercopy', 'tkl_merge_module', 'tkl_get_parent_imported_module_state', 'tkl_declare_global', 'tkl_import_module', 'TackleSourceModuleState', 'tkl_source_module', 'TackleLocalImportModuleState', 'testlib', 'testlib_std1', 'testlib.std3', 'base_test'])
base_test
std1_test
std2_test
std3_test
Testé en Python 3.7.4
, 3.2.5
,2.7.16
Avantages :
testlib.std.py
as testlib
, testlib.blabla.py
as testlib_blabla
et ainsi de suite).sys.path
ou d'un stockage de chemin de recherche.SOURCE_FILE
et SOURCE_DIR
entre les appels à tkl_import_module
.3.4.x
et supérieur] Peut mélanger les espaces de noms de module dans des tkl_import_module
appels imbriqués (ex: named->local->named
oulocal->named->local
et ainsi de suite).3.4.x
et supérieur] Peut exporter automatiquement les variables / fonctions / classes globales d'où elles sont déclarées à tous les modules enfants importés via tkl_import_module
(via la tkl_declare_global
fonction).Inconvénients :
3.3.x
et inférieur] Obligation de déclarer tkl_import_module
dans tous les modules qui appelle tkl_import_module
(duplication de code)Mise à jour 1,2 (pour 3.4.x
et supérieur uniquement):
Dans Python 3.4 et supérieur, vous pouvez contourner l'exigence de déclaration tkl_import_module
dans chaque module en déclarant tkl_import_module
dans un module de niveau supérieur et la fonction s'injecterait à tous les modules enfants en un seul appel (c'est une sorte d'importation auto-déployée).
Mise à jour 3 :
Ajout d'une fonction tkl_source_module
analogique à bash source
avec prise en charge de l'exécution lors de l'importation (implémentée via la fusion du module au lieu de l'importation).
Mise à jour 4 :
Ajout d'une fonction tkl_declare_global
pour exporter automatiquement une variable globale de module vers tous les modules enfants où une variable globale de module n'est pas visible car ne fait pas partie d'un module enfant.
Mise à jour 5 :
Toutes les fonctions ont été déplacées dans la bibliothèque tacklelib, voir le lien ci-dessus.
Il existe un package spécifiquement dédié à cela:
from thesmuggler import smuggle
# À la `import weapons`
weapons = smuggle('weapons.py')
# À la `from contraband import drugs, alcohol`
drugs, alcohol = smuggle('drugs', 'alcohol', source='contraband.py')
# À la `from contraband import drugs as dope, alcohol as booze`
dope, booze = smuggle('drugs', 'alcohol', source='contraband.py')
Il est testé sur toutes les versions de Python (Jython et PyPy aussi), mais il peut être excessif en fonction de la taille de votre projet.
Ajout de cela à la liste des réponses car je n'ai rien trouvé qui fonctionnait. Cela permettra d'importer des 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()
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 gardien, vous pouvez enfin obtenir un très long chemin
Une solution simple utilisant à la importlib
place du imp
package (testée pour Python 2.7, bien qu'elle 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")
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 l'utiliser dans notre code. Ceci est utile, par exemple dans le cas où le chemin du module est un argument configurable.
sys.path
, qui ne convient pas à tous les cas d'utilisation.
sys.path.pop()
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 rapide et sale d'obtenir le nom probable du module python avec un nom de fichier - il monte simplement dans l'arborescence jusqu'à ce qu'il trouve un répertoire sans __init__.py
fichier, puis le retourne en 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 __init__.py
fichiers optionnels peuvent nécessiter d'autres modifications, mais si vous en avez __init__.py
en général, cela fait l'affaire.
La meilleure façon, je pense, est de la documentation officielle ( 29.1. Imp - Accéder aux importations internes ):
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()