Come posso caricare un modulo Python dato il suo percorso completo? Nota che il file può trovarsi ovunque nel filesystem, in quanto è un'opzione di configurazione.
Come posso caricare un modulo Python dato il suo percorso completo? Nota che il file può trovarsi ovunque nel filesystem, in quanto è un'opzione di configurazione.
Risposte:
Per Python 3.5+ utilizzare:
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 usare:
from importlib.machinery import SourceFileLoader
foo = SourceFileLoader("module.name", "/path/to/file.py").load_module()
foo.MyClass()
(Anche se questo è 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 e le DLL Python compilati.
Vedi anche http://bugs.python.org/issue21436 .
__import__
.
imp.load_source
imposta solo .__name__
il modulo restituito. non ha effetto sul caricamento.
imp.load_source()
determina la chiave della nuova voce creata nel sys.modules
dizionario, quindi il primo argomento influisce sul caricamento.
imp
modulo è obsoleto dalla versione 3.4: il imp
pacchetto è in attesa di svalutazione a favore di importlib
.
Il vantaggio di aggiungere un percorso a sys.path (oltre a usare 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
sys.path.append
per puntare a un singolo file Python invece che a una directory?
importlib.import_module(mod_name)
può essere usato al posto dell'importazione esplicita qui se il nome del modulo non è noto in fase di runtime, aggiungerei un sys.path.pop()
alla fine, tuttavia, supponendo che il codice importato non tenti di importare più moduli mentre viene utilizzato.
Se il modulo di livello superiore non è un file ma è impacchettato come directory con __init__.py, la soluzione accettata funziona quasi, 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, cerca 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 è stato ancora caricato, quindi verrà visualizzato l'errore "SystemError: modulo genitore 'mymodule' non caricato, impossibile eseguire l'importazione relativa". Quindi è necessario associare il nome prima di caricarlo. La ragione di ciò è il fondamentale invariante del relativo sistema di importazione: "La tenuta invariante è che se hai sys.modules ['spam'] e sys.modules ['spam.foo'] (come faresti dopo l'importazione sopra ), quest'ultimo deve apparire come l'attributo foo del primo ", come discusso qui .
mymodule
?
/path/to/your/module/
è in realtà /path/to/your/PACKAGE/
? e mymodule
intendi myfile.py
?
Per importare il tuo modulo, devi aggiungere la sua directory alla variabile d'ambiente, temporaneamente o permanentemente.
import sys
sys.path.append("/path/to/my/modules/")
import my_module
Aggiungendo la seguente riga al tuo .bashrc
file (in Linux) ed esegui source ~/.bashrc
nel terminale:
export PYTHONPATH="${PYTHONPATH}:/path/to/my/modules/"
Credito / Fonte: saarrrr , un'altra domanda di scambio di stack
Sembra che tu non voglia importare in modo specifico il file di configurazione (che ha molti effetti collaterali e ulteriori complicazioni), vuoi 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")
Tale interfaccia è disponibile in Python 2.7 e Python 3.2+
result[name]
, result.get('name', default_value)
, ecc)
from runpy import run_path; from argparse import Namespace; mod = Namespace(**run_path('path/to/file.py'))
Puoi anche fare qualcosa del genere e aggiungere la directory in cui si trova il file di configurazione nel percorso di caricamento di Python, quindi eseguire un'importazione normale, supponendo che tu conosca in anticipo il nome del file, 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
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:
clausola generale è raramente una buona idea.
save_cwd = os.getcwd()
try: …
finally: os.chdir(save_cwd)
this is already addressed by the standard library
sì, ma Python ha la brutta abitudine di non essere retrocompatibile ... poiché la risposta selezionata dice che ci sono 2 modi diversi prima e dopo 3.3. In tal caso, preferirei scrivere la mia funzione universale piuttosto che controllare la versione al volo. E sì, forse questo codice non è protetto troppo bene dagli errori, ma mostra un'idea (che è os.chdir (), non ci ho pensato), in base al quale posso scrivere un codice migliore. Quindi +1.
Ecco del codice che funziona in tutte le versioni di Python, dalla 2.7-3.5 e probabilmente anche in altre.
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.
load_source
non lo è perché importa lo script e fornisce allo script l'accesso ai moduli e ai globali al momento dell'importazione.
Ho escogitato una versione leggermente modificata della meravigliosa risposta di @ SebastianRittau (per Python> 3.4 credo), che ti permetterà di caricare un file con qualsiasi estensione come 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 modo esplicito SourceFileLoader
è che il macchinario non proverà a capire il tipo di file dall'estensione. Questo significa che puoi caricare qualcosa come un .txt
file usando questo metodo, ma non puoi farlo spec_from_file_location
senza specificare il caricatore perché .txt
non è in importlib.machinery.SOURCE_SUFFIXES
.
Intendi caricare o importare?
È possibile manipolare l' sys.path
elenco, specificare il percorso del modulo, quindi importare il modulo. Ad esempio, dato un modulo su:
/foo/bar.py
Potresti fare:
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.
Quindi perché non sys.path.insert(0, ...)
invece di sys.path[0:0]
?
Credo che tu possa usare imp.find_module()
e imp.load_module()
caricare il modulo specificato. Dovrai dividere il nome del modulo fuori dal percorso, ad esempio se desideri caricare /home/mypath/mymodule.py
devi fare:
imp.find_module('mymodule', '/home/mypath/')
... ma questo dovrebbe portare a termine il lavoro.
È possibile utilizzare il pkgutil
modulo (in particolare il walk_packages
metodo) per ottenere un elenco dei pacchetti nella directory corrente. Da lì è banale usare i importlib
macchinari per importare i moduli desiderati:
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!
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.
Questa area di Python 3.4 sembra essere estremamente tortuosa da capire! Tuttavia, con un po 'di hacking utilizzando 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
Questo sembra usare moduli non deprecati da Python 3.4. Non pretendo di capire il perché, ma sembra funzionare all'interno di un programma. Ho scoperto che la soluzione di Chris funzionava dalla riga di comando ma non dall'interno di un programma.
Non sto dicendo che sia meglio, ma per completezza, ho voluto suggerire che la exec
funzione, disponibile sia in Python 2 che in 3.
exec
consente di eseguire codice arbitrario in ambito globale o in ambito interno, fornito come dizionario.
Ad esempio, se si dispone di un modulo memorizzato in "/path/to/module
"con la funzione foo()
, è possibile eseguirlo nel modo seguente:
module = dict()
with open("/path/to/module") as f:
exec(f.read(), module)
module['foo']()
Ciò rende un po 'più esplicito il caricamento dinamico del codice e garantisce ulteriore potenza, ad esempio la possibilità di fornire built-in personalizzati.
E se avere accesso attraverso gli attributi, anziché le chiavi è importante per te, puoi progettare una classe dict personalizzata per i globi, che fornisca tale accesso, ad esempio:
class MyModuleClass(dict):
def __getattr__(self, name):
return self.__getitem__(name)
Per importare un modulo da un determinato nome file, è possibile estendere temporaneamente il percorso e ripristinare il percorso di sistema nel riferimento del blocco finally :
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
Se disponiamo di script nello stesso progetto ma in directory diverse, possiamo risolvere questo problema con il seguente metodo.
In questa situazione utils.py
è dentrosrc/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
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)
name, ext = os.path.splitext(os.path.basename(infile))
. Il tuo metodo funziona perché la precedente limitazione all'estensione .py. Inoltre, dovresti probabilmente importare il modulo in qualche voce variabile / dizionario.
Ho creato un pacchetto che utilizza imp
per te. Lo chiamo import_file
ed è così che viene utilizzato:
>>>from import_file import import_file
>>>mylib = import_file('c:\\mylib.py')
>>>another = import_file('relative_subdir/another.py')
Puoi ottenerlo su:
http://pypi.python.org/pypi/import_file
o a
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 lo 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 includere quanto segue in mypythonscript.py
from module import *
git
e controllando il proprio git status
per verificare che le modifiche apportate allo script stiano effettivamente tornando al documento di origine e non si perdano nell'etere.
Ho scritto la mia funzione di importazione globale e portatile, basata sul importlib
modulo, per:
sys.path
o su qualsiasi memoria del percorso di ricerca.La struttura di directory degli esempi:
<root>
|
+- test.py
|
+- testlib.py
|
+- /std1
| |
| +- testlib.std1.py
|
+- /std2
| |
| +- testlib.std2.py
|
+- /std3
|
+- testlib.std3.py
Dipendenza e ordine dell'inclusione:
test.py
-> testlib.py
-> testlib.std1.py
-> testlib.std2.py
-> testlib.std3.py
Implementazione:
Archivio delle ultime modifiche: 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')
Uscita ( 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
Testato in Python 3.7.4
, 3.2.5
,2.7.16
Pro :
testlib.std.py
come testlib
, testlib.blabla.py
come testlib_blabla
e così via).sys.path
o da un archivio di percorsi di ricerca.SOURCE_FILE
e SOURCE_DIR
tra le chiamate a tkl_import_module
.3.4.x
e successive] Può mescolare gli spazi dei nomi del modulo in tkl_import_module
chiamate nidificate (es: named->local->named
o local->named->local
così via).3.4.x
e successivi] Può esportare automaticamente variabili / funzioni / classi globali da dove viene dichiarato a tutti i moduli figli importati attraverso tkl_import_module
(attraverso la tkl_declare_global
funzione).Contro :
3.3.x
e inferiore] Richiesta di dichiarazione tkl_import_module
in tutti i moduli che chiama a tkl_import_module
(duplicazione del codice)Aggiornamento 1,2 (solo per 3.4.x
e successivi):
In Python 3.4 e versioni successive è possibile ignorare il requisito di dichiarare tkl_import_module
in ciascun modulo dichiarando tkl_import_module
in un modulo di livello superiore e la funzione si inietterebbe da sola in tutti i moduli figlio in una singola chiamata (è una specie di importazione self-deploy).
Aggiornamento 3 :
Aggiunta funzione tkl_source_module
come analogica per bash source
con supporto per la protezione dell'esecuzione al momento dell'importazione (implementata tramite l'unione del modulo anziché l'importazione).
Aggiornamento 4 :
Aggiunta funzione tkl_declare_global
per esportare automaticamente una variabile globale del modulo in tutti i moduli figlio in cui una variabile globale del modulo non è visibile perché non fa parte di un modulo figlio.
Aggiornamento 5 :
Tutte le funzioni sono state spostate nella libreria tacklelib, vedere il link sopra.
C'è un pacchetto dedicato a questo in particolare:
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')
È testato su tutte le versioni di Python (anche Jython e PyPy), ma potrebbe essere eccessivo a seconda delle dimensioni del progetto.
Aggiungendo questo all'elenco delle risposte in quanto non riuscivo a 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()
modo abbastanza semplice: supponiamo di voler importare il file con 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 al importlib
posto del imp
pacchetto (testato per Python 2.7, anche se 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 utilizzare direttamente lo spazio dei nomi del modulo importato, in questo modo:
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 , al fine di utilizzarlo nel nostro codice. Ciò è utile, ad esempio nel caso in cui il percorso del modulo sia un argomento configurabile.
sys.path
, che non si adatta a tutti i casi d'uso.
sys.path.pop()
Questa risposta è un supplemento alla risposta di Sebastian Rittau che risponde al commento: "ma cosa succede se non si dispone del nome del modulo?" Questo è un modo rapido e sporco per ottenere il nome del modulo Python probabile dato un nome di file - sale solo fino a quando non trova una directory senza un __init__.py
file e poi lo trasforma in un nome file. Per Python 3.4+ (usa pathlib), il che ha senso dato che le persone Py2 possono usare "imp" o altri modi di fare le relative importazioni:
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 __init__.py
file opzionali potrebbero richiedere altre modifiche, ma se hai __init__.py
in generale, questo fa il trucco.
Il modo migliore, penso, è dalla documentazione ufficiale ( 29.1. Imp - Accedi agli import interni ):
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()