it-swarm.it

Come importare un modulo dato il percorso completo?

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.

922
derfred

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 .

1055
Sebastian Rittau

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
358
Daryl Spitzer

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

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+

19
ncoghlan

Puoi usare il

load_source(module_name, path_to_file) 

metodo da modulo imp .

16
zuber

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 .

13
Mad Physicist

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

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 .

12
Sam Grondahl

Per importare il tuo modulo, devi aggiungere la sua directory alla variabile di ambiente, temporaneamente o permanentemente.

Temporaneamente

import sys
sys.path.append("/path/to/my/modules/")
import my_module

Permanentemente

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

11
Miladiouss

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.

11
sorin
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')
10
Chris Calloway

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.

8
Matt

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.

3
abhimanyu

È 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!
3
bob_twinkles

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)
3
Hengjie

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)
3
yoniLavi

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.

3
Redlegjed

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
3
Peter Zhu

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)
2
user10370

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 *
2
user2760152

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

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

2
ubershmekel

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

1
Andrei Keino

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.

1
Ataxias

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()
0
David

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.