it-swarm-pt.tech

Como importar um módulo dado o caminho completo?

Como posso carregar um módulo Python dado seu caminho completo? Observe que o arquivo pode estar em qualquer lugar no sistema de arquivos, pois é uma opção de configuração.

922
derfred

Para uso do Python 3.5+:

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 e 3.4, use:

from importlib.machinery import SourceFileLoader

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

(Embora isso tenha sido preterido no Python 3.4.)

Para uso do Python 2:

import imp

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

Existem funções de conveniência equivalentes para arquivos e DLLs compilados em Python.

Veja também http://bugs.python.org/issue21436 .

1055
Sebastian Rittau

A vantagem de adicionar um caminho para sys.path (sobre o uso de imp) é que ele simplifica as coisas ao importar mais de um módulo de um único pacote. Por exemplo:

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

Você também pode fazer algo parecido com isto e adicionar o diretório no qual o arquivo de configuração está inserido no caminho de carregamento do Python e, em seguida, fazer uma importação normal, supondo que você saiba o nome do arquivo antecipadamente, neste caso "config".

Sujo, mas funciona.

configfile = '~/config.py'

import os
import sys

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

import config
19
ctcherry

Parece que você não quer importar especificamente o arquivo de configuração (que tem muitos efeitos colaterais e complicações adicionais envolvidas), você só quer executá-lo e ser capaz de acessar o namespace resultante. A biblioteca padrão fornece uma API especificamente para isso na forma de runpy.run_path :

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

Essa interface está disponível no Python 2.7 e no Python 3.2+

19
ncoghlan

Você pode usar o

load_source(module_name, path_to_file) 

método do imp module .

16
zuber

Eu vim com uma versão ligeiramente modificada de @ maravilhosa resposta de SebastianRittau (para Python> 3.4 eu acho), que lhe permitirá carregar um arquivo com qualquer extensão como um módulo usando spec_from_loader em vez 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)

A vantagem de codificar o caminho em uma opção explícita SourceFileLoader é que o maquinário não tentará descobrir o tipo do arquivo da extensão. Isso significa que você pode carregar algo como um arquivo .txt usando este método, mas você não pode fazer isso com spec_from_file_location sem especificar o carregador porque .txt não está em importlib.machinery.SOURCE_SUFFIXES .

13
Mad Physicist

Você quer dizer carregar ou importar?

Você pode manipular a lista sys.path para especificar o caminho para o seu módulo e depois importar o seu módulo. Por exemplo, dado um módulo em:

/foo/bar.py

Você poderia fazer:

import sys
sys.path[0:0] = ['/foo'] # puts the /foo directory at the start of your path
import bar
12
Wheat

Se o seu módulo de nível superior não é um arquivo, mas é empacotado como um diretório com __init__.py, então a solução aceita quase funciona, mas não completamente. No Python 3.5+, o seguinte código é necessário (observe a linha adicionada que começa com '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)

Sem essa linha, quando exec_module é executado, ele tenta vincular as importações relativas em seu nível superior __init__.py ao nome do módulo de nível superior - nesse caso, "mymodule". Mas "mymodule" ainda não está carregado, então você receberá o erro "SystemError: Parent module 'mymodule' não carregado, não pode executar uma importação relativa". Então você precisa ligar o nome antes de carregá-lo. A razão para isso é a invariante fundamental do sistema de importação relativo: "A invariante é que se você tiver sys.modules ['spam'] e sys.modules ['spam.foo'] (como você faria após a importação acima ), este último deve aparecer como o atributo foo do primeiro " como discutido aqui .

12
Sam Grondahl

Para importar seu módulo, você precisa adicionar seu diretório à variável de ambiente, temporária ou permanentemente.

Temporariamente

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

Permanentemente

Adicionando a seguinte linha ao seu arquivo .bashrc (no linux) e execute source ~/.bashrc no terminal:

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

Crédito/Fonte: saarrrr , outra questão de troca de pilha

11
Miladiouss

Aqui está algum código que funciona em todas as versões do Python, de 2.7-3.5 e provavelmente até mesmo outras.

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

Eu testei isso. Pode ser feio, mas até agora é o único que funciona em todas as versões.

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

Eu acredito que você pode usar imp.find_module() e imp.load_module() para carregar o módulo especificado. Você precisará dividir o nome do módulo do caminho, ou seja, se quiser carregar /home/mypath/mymodule.py, será necessário fazer o seguinte:

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

... mas isso deve fazer o trabalho.

8
Matt

Crie o módulo python test.py

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

Crie o módulo python test_check.py

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

Nós podemos importar o módulo importado do módulo.

3
abhimanyu

Você pode usar o módulo pkgutil (especificamente o método walk_packages ) para obter uma lista dos pacotes no diretório atual. A partir daí, é trivial usar a maquinaria importlib para importar os módulos que você deseja:

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

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

Eu não estou dizendo que é melhor, mas por questão de completude, eu queria sugerir a função exec , disponível tanto no python 2 como no 3. exec permite que você execute código arbitrário no escopo global, ou em um escopo interno, fornecido como um dicionário.

Por exemplo, se você tiver um módulo armazenado em "/path/to/module "com a função foo(), poderá executá-lo da seguinte maneira:

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

Isso torna um pouco mais explícito que você está carregando código dinamicamente e concede a você algum poder adicional, como a capacidade de fornecer builtins personalizados.

E se ter acesso através de atributos, em vez de chaves, é importante para você, você pode criar uma classe de dit customizada para os globais, que fornece esse acesso, por exemplo:

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

Esta área do Python 3.4 parece ser extremamente tortuosa para entender! No entanto, com um pouco de hacking usando o código de Chris Calloway como um começo, consegui algo funcionando. Aqui está a função 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

Isso parece usar módulos não obsoletos do Python 3.4. Eu não pretendo entender o porquê, mas parece funcionar dentro de um programa. Eu encontrei a solução de Chris trabalhou na linha de comando, mas não de dentro de um programa.

3
Redlegjed

Para importar um módulo de um determinado nome de arquivo, você pode estender temporariamente o caminho e restaurar o caminho do sistema no bloco final 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

Importar módulos de pacote em tempo de execução (receita do 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

No Linux, adicionar um link simbólico no diretório que seu script python está localizado funciona.

ie:

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

python criará /absolute/path/to/script/module.pyc e atualizará se você alterar o conteúdo de /absolute/path/to/module/module.py

em seguida, inclua o seguinte em mypythonscript.py

from module import *
2
user2760152

Eu fiz um pacote que usa imp para você. Eu chamo-lhe import_file e é assim que é usado:

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

Você pode obtê-lo em:

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

ou em

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

2
ubershmekel

maneira bastante simples: suponha que você deseja importar o arquivo com o caminho relativo ../../MyLibs/pyfunc.py


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

Mas se você fizer isso sem um guarda, você pode finalmente obter um caminho muito longo

1
Andrei Keino

Uma solução simples usando importlib em vez do pacote imp (testado para o Python 2.7, embora também funcione para o 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")

Agora você pode usar diretamente o namespace do módulo importado, assim:

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

A vantagem desta solução é que nós nem precisamos saber o nome real do módulo que gostaríamos de importar , para usá-lo em nosso código. Isso é útil, por ex. caso o caminho do módulo seja um argumento configurável.

1
Ataxias

Adicionando isso à lista de respostas, eu não consegui encontrar nada que funcionasse. Isso permitirá a importação de módulos python (pyd) compilados em 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

Esta resposta é um complemento à resposta de Sebastian Rittau, respondendo ao comentário: "mas e se você não tiver o nome do módulo?" Esta é uma maneira rápida e suja de obter o nome provável do módulo python dado um nome de arquivo - ele simplesmente sobe na árvore até encontrar um diretório sem um arquivo __init__.py e, em seguida, o transforma de volta em um nome de arquivo. Para o Python 3.4+ (usa pathlib), o que faz sentido, já que o Py2 pode usar "imp" ou outras maneiras de fazer importações 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))

Certamente há possibilidades de melhoria, e os arquivos __init__.py opcionais podem necessitar de outras alterações, mas se você tiver __init__.py em geral, isso é o suficiente.

0
Michael Scott Cuthbert