Pregunta

¿Cómo puedo cargar un módulo de Python dada su ruta completa?Tenga en cuenta que el archivo puede estar en cualquier parte del sistema de archivos, ya que es una opción de configuración.

¿Fue útil?

Solución

Para Python 3.5+ use:

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

Para Python 3.3 y 3.4 use:

from importlib.machinery import SourceFileLoader

foo = SourceFileLoader("module.name", "/path/to/file.py").load_module()
foo.MyClass()

(Aunque esto ha quedado obsoleto en Python 3.4).

Para uso de Python 2:

import imp

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

Existen funciones de conveniencia equivalentes para archivos DLL y archivos Python compilados.

Ver también http://bugs.python.org/issue21436.

Otros consejos

La ventaja de agregar una ruta a sys.path (en lugar de usar imp) es que simplifica las cosas al importar más de un módulo desde un solo paquete.Por ejemplo:

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

También puede hacer algo como esto y agregar el directorio en el que se encuentra el archivo de configuración a la ruta de carga de Python, y luego simplemente realizar una importación normal, asumiendo que conoce el nombre del archivo de antemano, en este caso "config".

Confuso, pero funciona.

configfile = '~/config.py'

import os
import sys

sys.path.append(os.path.dirname(os.path.expanduser(configfile)))

import config

Parece que no desea importar específicamente el archivo de configuración (que tiene muchos efectos secundarios y complicaciones adicionales), solo desea ejecutarlo y poder acceder al espacio de nombres resultante.La biblioteca estándar proporciona una API específicamente para eso en forma de runpy.run_path:

from runpy import run_path
settings = run_path("/path/to/file.py")

Esa interfaz está disponible en Python 2.7 y Python 3.2+

Puedes usar el

load_source(module_name, path_to_file) 

método de módulo diablillo.

Si su módulo de nivel superior no es un archivo sino que está empaquetado como un directorio con __init__.py, entonces la solución aceptada casi funciona, pero no del todo.En Python 3.5+ se necesita el siguiente código (tenga en cuenta la línea agregada que comienza 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)

Sin esta línea, cuando se ejecuta exec_module, intenta vincular las importaciones relativas en su nivel superior __init__.py al nombre del módulo de nivel superior, en este caso "mymodule".Pero "mymodule" aún no está cargado, por lo que aparecerá el error "SystemError:El módulo principal 'mymodule' no está cargado, no se puede realizar una importación relativa".Por lo tanto, debe vincular el nombre antes de cargarlo.La razón de esto es la invariante fundamental del sistema de importación relativa:"La invariante es que si tiene sys.modules['spam'] y sys.modules['spam.foo'] (como lo haría después de la importación anterior), este último debe aparecer como el atributo foo del primero" como se discute aquí.

He creado una versión ligeramente modificada de La maravillosa respuesta de @SebastianRittau (para Python > 3.4, creo), lo que le permitirá cargar un archivo con cualquier extensión como módulo usando spec_from_loader en lugar 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)

La ventaja de codificar la ruta de forma explícita. SourceFileLoader es que el maquinaria no intentará averiguar el tipo de archivo a partir de la extensión.Esto significa que puedes cargar algo como un .txt archivo usando este método, pero no podrías hacerlo con spec_from_file_location sin especificar el cargador porque .txt no está dentro importlib.machinery.SOURCE_SUFFIXES.

Aquí hay un código que funciona en todas las versiones de Python, desde la 2.7 a la 3.5 y probablemente incluso en otras.

config_file = "/tmp/config.py"
with open(config_file) as f:
    code = compile(f.read(), config_file, 'exec')
    exec(code, globals(), locals())

Lo probé.Puede que sea feo pero hasta el momento es el único que funciona en todas las versiones.

Para importar su módulo, debe agregar su directorio a la variable de entorno, ya sea de forma temporal o permanente.

Temporalmente

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

Permanentemente

Agregando la siguiente línea a su .bashrc archivo (en Linux) y ejecutar source ~/.bashrc en la terminal:

export PYTHONPATH="${PYTHONPATH}:/path/to/my/modules/"

Crédito/Fuente: sarrrrr, otra pregunta de intercambio de pila

¿Te refieres a cargar o importar?

Puede manipular la lista sys.path, especificar la ruta a su módulo y luego importar su módulo.Por ejemplo, dado un módulo en:

/foo/bar.py

Podrías hacerlo:

import sys
sys.path[0:0] = ['/foo'] # puts the /foo directory at the start of your path
import bar
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')

Creo que puedes usar imp.find_module() y imp.load_module() para cargar el módulo especificado.Deberá dividir el nombre del módulo de la ruta, es decirsi quisieras cargar /home/mypath/mymodule.py necesitarías hacer:

imp.find_module('mymodule', '/home/mypath/')

...pero eso debería hacer el trabajo.

Esto debería funcionar

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)

Puedes usar el pkgutil módulo (específicamente el walk_packages método) para obtener una lista de los paquetes en el directorio actual.A partir de ahí es trivial utilizar el importlib Maquinaria para importar los módulos que desees:

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!

¡Esta área de Python 3.4 parece extremadamente tortuosa de entender!Sin embargo, con un poco de piratería usando el código de Chris Calloway como comienzo, logré que algo funcionara.Aquí está la función básica.

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

Esto parece utilizar módulos no obsoletos de Python 3.4.No pretendo entender por qué, pero parece funcionar desde dentro de un programa.Descubrí que la solución de Chris funcionaba en la línea de comandos pero no desde dentro de un programa.

No digo que sea mejor, pero para completar, quería sugerir la exec función, disponible tanto en Python 2 como en 3.exec le permite ejecutar código arbitrario en el ámbito global o en un ámbito interno, proporcionado como un diccionario.

Por ejemplo, si tiene un módulo almacenado en "/path/to/module" con la función foo(), puedes ejecutarlo haciendo lo siguiente:

module = dict()
with open("/path/to/module") as f:
    exec(f.read(), module)
module['foo']()

Esto hace que sea un poco más explícito que estás cargando código dinámicamente y te otorga algo de potencia adicional, como la capacidad de proporcionar funciones integradas personalizadas.

Y si para usted es importante tener acceso a través de atributos, en lugar de claves, puede diseñar una clase dict personalizada para los globales, que proporcione dicho acceso, por ejemplo:

class MyModuleClass(dict):
    def __getattr__(self, name):
        return self.__getitem__(name)

Para importar un módulo desde un nombre de archivo determinado, puede extender temporalmente la ruta y restaurar la ruta del sistema en el bloque finalmente. referencia:

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

Crear módulo de Python test.py

import sys
sys.path.append("<project-path>/lib/")
from tes1 import Client1
from tes2 import Client2
import tes3

Crear módulo de Python test_check.py

from test import Client1
from test import Client2
from test import test3

Podemos importar el módulo importado desde module.

Hice un paquete que usa imp para ti.yo lo llamo import_file y así es como se usa:

>>>from import_file import import_file
>>>mylib = import_file('c:\\mylib.py')
>>>another = import_file('relative_subdir/another.py')

Puedes conseguirlo en:

http://pypi.python.org/pypi/import_file

o en

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

Importar módulos de paquetes en tiempo de ejecución (receta de 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)

En Linux, funciona agregar un enlace simbólico en el directorio donde se encuentra su script de Python.

es decir:

ln -s /absolute/path/to/module/module.py /absolute/path/to/script/module.py

Python creará /absolute/path/to/script/module.pyc y lo actualizará si cambia el contenido de /absolute/path/to/module/module.py

luego incluya lo siguiente en mypythonscript.py

from module import *

forma bastante sencilla:supongamos que desea importar un archivo con una ruta relativa ../../MyLibs/pyfunc.py


libPath = '../../MyLibs'
import sys
if not libPath in sys.path: sys.path.append(libPath)
import pyfunc as pf

Pero si lo haces sin guardia, finalmente podrás conseguir un camino muy largo.

Una solución sencilla utilizando importlib en vez de imp paquete (probado para Python 2.7, aunque debería funcionar también para 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")

Ahora puedes usar directamente el espacio de nombres del módulo importado, así:

a = module.myvar
b = module.myfunc(a)

La ventaja de esta solución es que ni siquiera necesitamos saber el nombre real del módulo que nos gustaría importar, para poder usarlo en nuestro código.Esto es útil, p.e.en caso de que la ruta del módulo sea un argumento configurable.

Agregué esto a la lista de respuestas porque no pude encontrar nada que funcionara.Esto permitirá importar módulos de Python compilados (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()

Esta respuesta es un complemento a la respuesta de Sebastian Rittau al comentario:"¿Pero qué pasa si no tienes el nombre del módulo?" Esta es una forma rápida y sucia de obtener el probable nombre del módulo Python dado un nombre de archivo: simplemente sube por el árbol hasta que encuentra un directorio sin un __init__.py archivo y luego lo convierte nuevamente en un nombre de archivo.Para Python 3.4+ (usa pathlib), lo cual tiene sentido ya que la gente de Py2 puede usar "imp" u otras formas de realizar importaciones relativas:

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

Ciertamente hay posibilidades de mejora, y la opción opcional __init__.py Los archivos pueden necesitar otros cambios, pero si tiene __init__.py en general, esto funciona.

Creo que la mejor manera es a partir de la documentación oficial (29.1.imp — Accede a las partes internas de importación):

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()
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top