Come posso caricare un modulo Python dato il suo percorso completo? Si noti che il file può essere ovunque nel filesystem, in quanto è un'opzione di configurazione.
Per Python 3.5+ usi:
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()
Per Python 3.3 e 3.4 utilizzare:
from importlib.machinery import SourceFileLoader
foo = SourceFileLoader("module.name", "/path/to/file.py").load_module()
foo.MyClass()
(Sebbene questo sia stato deprecato in Python 3.4.)
Per Python 2 usare:
import imp
foo = imp.load_source('module.name', '/path/to/file.py')
foo.MyClass()
Esistono funzioni di convenienza equivalenti per i file Python compilati e le DLL.
Vedi anche http://bugs.python.org/issue21436 .
Il vantaggio di aggiungere un percorso a sys.path (rispetto all'utilizzo di imp) è che semplifica le cose quando si importa più di un modulo da un singolo pacchetto. Per esempio:
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
Puoi anche fare qualcosa di simile e aggiungere la directory in cui si trova il file di configurazione nel percorso di caricamento di Python, e quindi fare semplicemente un'importazione normale, assumendo che tu conosca il nome del file in anticipo, in questo caso "config".
Disordinato, ma funziona.
configfile = '~/config.py'
import os
import sys
sys.path.append(os.path.dirname(os.path.expanduser(configfile)))
import config
Sembra che tu non voglia importare in modo specifico il file di configurazione (che ha un sacco di effetti collaterali e complicazioni aggiuntive), devi solo eseguirlo ed essere in grado di accedere allo spazio dei nomi risultante. La libreria standard fornisce un'API specifica per questo sotto forma di runpy.run_path :
from runpy import run_path
settings = run_path("/path/to/file.py")
Quell'interfaccia è disponibile in Python 2.7 e Python 3.2+
Ho trovato una versione leggermente modificata di @ La meravigliosa risposta di SebastianRittau (per Python> 3.4 Penso), che ti permetterà di caricare un file con qualsiasi estensione come un modulo usando spec_from_loader
invece di 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)
Il vantaggio di codificare il percorso in un SourceFileLoader
è che machinery non tenterà di capire il tipo di file dall'estensione. Questo significa che puoi caricare qualcosa come un file .txt
usando questo metodo, ma non puoi farlo con spec_from_file_location
senza specificare il loader perché .txt
non è in importlib.machinery.SOURCE_SUFFIXES
.
Vuoi dire caricare o importare?
È possibile manipolare l'elenco sys.path specificando il percorso del modulo, quindi importare il modulo. Ad esempio, dato un modulo a:
/foo/bar.py
Potresti fare:
import sys
sys.path[0:0] = ['/foo'] # puts the /foo directory at the start of your path
import bar
Se il tuo modulo di primo livello non è un file ma è impacchettato come una directory con __init__.py, allora la soluzione accettata quasi funziona, ma non del tutto. In Python 3.5+ è necessario il seguente codice (notare la riga aggiunta che inizia con "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)
Senza questa riga, quando exec_module viene eseguito, tenta di associare le importazioni relative nel tuo livello superiore __init__.py al nome del modulo di livello superiore, in questo caso "mymodule". Ma "mymodule" non è ancora caricato, quindi riceverai l'errore "SystemError: il modulo padre 'mymodule' non è stato caricato, non è possibile eseguire l'importazione relativa". Quindi è necessario associare il nome prima di caricarlo. La ragione di ciò è l'invariante fondamentale del relativo sistema di importazione: "L'invariant holding è che se hai sys.modules ['spam'] e sys.modules ['spam.foo'] (come faresti dopo l'importazione di cui sopra ), quest'ultimo deve apparire come l'attributo foo del precedente " come discusso qui .
Per importare il tuo modulo, devi aggiungere la sua directory alla variabile di ambiente, temporaneamente o permanentemente.
import sys
sys.path.append("/path/to/my/modules/")
import my_module
Aggiungendo la seguente riga al proprio file .bashrc
(in linux) ed eccecando source ~/.bashrc
nel terminale:
export PYTHONPATH="${PYTHONPATH}:/path/to/my/modules/"
Credito/Fonte: saarrrr , un'altra domanda stackexchange
Ecco un codice che funziona in tutte le versioni di Python, dal 2.7-3.5 e probabilmente anche da altri.
config_file = "/tmp/config.py"
with open(config_file) as f:
code = compile(f.read(), config_file, 'exec')
exec(code, globals(), locals())
L'ho provato Può essere brutto, ma finora è l'unico che funziona in tutte le versioni.
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')
Credo che tu possa usare imp.find_module()
e imp.load_module()
per caricare il modulo specificato. Dovrai dividere il nome del modulo al di fuori del percorso, cioè se volessi caricare /home/mypath/mymodule.py
avresti bisogno di fare:
imp.find_module('mymodule', '/home/mypath/')
... ma dovrebbe portare a termine il lavoro.
Crea il modulo python test.py
import sys
sys.path.append("<project-path>/lib/")
from tes1 import Client1
from tes2 import Client2
import tes3
Crea il modulo python test_check.py
from test import Client1
from test import Client2
from test import test3
Possiamo importare il modulo importato dal modulo.
È possibile utilizzare il modulo pkgutil
(in particolare il metodo walk_packages
) per ottenere un elenco dei pacchetti nella directory corrente. Da lì è banale usare la macchina importlib
per importare i moduli che vuoi:
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!
Questo dovrebbe funzionare
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)
Non sto dicendo che è meglio, ma per completezza, volevo suggerire la funzione exec
, disponibile in python 2 e 3. exec
consente di eseguire codice arbitrario nello scope globale, o in un ambito interno, fornito come dizionario.
Ad esempio, se hai un modulo memorizzato in "/path/to/module
"con la funzione foo()
, puoi eseguirlo effettuando le seguenti operazioni:
module = dict()
with open("/path/to/module") as f:
exec(f.read(), module)
module['foo']()
Ciò rende un po 'più esplicito il fatto che stai caricando il codice in modo dinamico e ti concede un po' di energia aggiuntiva, come la possibilità di fornire builtin personalizzati.
E se l'accesso tramite gli attributi, al posto delle chiavi è importante per te, puoi progettare una classe di dettatura personalizzata per le globali, che fornisce tale accesso, ad esempio:
class MyModuleClass(dict):
def __getattr__(self, name):
return self.__getitem__(name)
Questa area di Python 3.4 sembra essere estremamente tortuosa da capire! Comunque con un po 'di hacking usando il codice di Chris Calloway come inizio sono riuscito a far funzionare qualcosa. Ecco la funzione di 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
Sembra che usi moduli non deprecati da Python 3.4. Non pretendo di capire perché, ma sembra funzionare all'interno di un programma. Ho trovato che la soluzione di Chris funzionava sulla riga di comando ma non all'interno di un programma.
Per importare un modulo da un determinato nome file, puoi estendere temporaneamente il percorso e ripristinare il percorso di sistema nel blocco 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
Importa i moduli del pacchetto in fase di esecuzione (ricetta 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)
In Linux, l'aggiunta di un collegamento simbolico nella directory in cui si trova il tuo script python funziona.
vale a dire:
ln -s /absolute/path/to/module/module.py /absolute/path/to/script/module.py
python creerà /absolute/path/to/script/module.pyc
e lo aggiornerà se cambi il contenuto di /absolute/path/to/module/module.py
quindi includi quanto segue in mypythonscript.py
from module import *
Ho creato un pacchetto che usa imp
per te. Lo chiamo import_file
e questo è il modo in cui viene utilizzato:
>>>from import_file import import_file
>>>mylib = import_file('c:\\mylib.py')
>>>another = import_file('relative_subdir/another.py')
Puoi prenderlo a:
http://pypi.python.org/pypi/import_file
o a
abbastanza semplice: supponiamo di voler importare il file con il relativo percorso ../../MyLibs/pyfunc.py
libPath = '../../MyLibs'
import sys
if not libPath in sys.path: sys.path.append(libPath)
import pyfunc as pf
Ma se lo fai senza una guardia, puoi finalmente ottenere un percorso molto lungo
Una soluzione semplice che utilizza importlib
al posto del pacchetto imp
(testato per Python 2.7, sebbene dovrebbe funzionare anche per 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")
Ora puoi usare direttamente lo spazio dei nomi del modulo importato, come questo:
a = module.myvar
b = module.myfunc(a)
Il vantaggio di questa soluzione è che non abbiamo nemmeno bisogno di conoscere il nome effettivo del modulo che vorremmo importare , per poterlo usare nel nostro codice. Questo è utile, ad es. nel caso in cui il percorso del modulo sia un argomento configurabile.
Aggiungendo questo alla lista di risposte come non ho potuto trovare nulla che funzionasse. Ciò consentirà l'importazione di moduli python compilati (pyd) in 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()
Questa risposta è un supplemento alla risposta di Sebastian Rittau che risponde al commento: "ma cosa succede se non si ha il nome del modulo?" Questo è un modo veloce e sporco di ottenere il nome del modulo python che è probabile dato un nome di file: sale sull'albero fino a quando non trova una directory senza un file __init__.py
e poi la restituisce in un nome file. Per Python 3.4+ (utilizza pathlib), il che ha senso poiché le persone Py2 possono usare "imp" o altri modi di fare importazioni relative:
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))
Ci sono certamente possibilità di miglioramento, e i file __init__.py
opzionali potrebbero richiedere altre modifiche, ma se hai __init__.py
in generale, questo è il trucco.