operator - python modules or packages




Come importare un modulo dato il percorso completo? (16)

È possibile utilizzare il modulo pkgutil (in particolare il metodo walk_packages ) per ottenere un elenco dei pacchetti nella directory corrente. Da lì è banale usare i macchinari 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!

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.


Aggiungendo questo alla lista di risposte non ho trovato 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()

Ecco un codice che funziona in tutte le versioni di Python, da 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.



Il modo migliore, penso, è dalla documentazione ufficiale ( 29.1. Imp - Accedere agli interni di importazione ):

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

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

Non sto dicendo che è meglio, ma per completezza, volevo suggerire la funzione exec , disponibile in python 2 e 3. exec ti permette di eseguire codice arbitrario sia nello scope globale, sia in un ambito, fornito come dizionario.

Ad esempio, se hai un modulo memorizzato in "/path/to/module " con la funzione foo() , puoi eseguirlo facendo quanto segue:

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 avere 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)

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.)

Python 2 usa:

import imp

foo = imp.load_source('module.name', '/path/to/file.py')
foo.MyClass()

Esistono funzioni di convenienza equivalenti per file e DLL Python compilati.

Guarda anche. http://bugs.python.org/issue21436 .


Puoi anche fare qualcosa di simile e aggiungere la directory in cui si trova il file di configurazione nel percorso di caricamento di Python, quindi effettuare 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

Puoi usare il

load_source(module_name, path_to_file) 

metodo dal modulo imp .


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 rapido e sporco di ottenere il nome del modulo Python che è probabile dato un nome di file: sale sull'albero solo fino a quando non trova una directory senza un file __init__.py e poi lo 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))

Esistono certamente possibilità di miglioramento e i file __init__.py facoltativi potrebbero richiedere altre modifiche, ma se hai __init__.py in generale, questo è il trucco.


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)

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+


Una soluzione semplice che utilizza importlib 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 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 è nemmeno necessario conoscere il nome effettivo del modulo che vorremmo importare , per poterlo utilizzare nel nostro codice. Questo è utile, ad esempio nel caso in cui il percorso del modulo sia un argomento configurabile.


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


Importa 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)




python-module