it-swarm-ru.tech

Как импортировать модуль с указанием полного пути?

Как я могу загрузить модуль Python, учитывая его полный путь? Обратите внимание, что файл может находиться где угодно в файловой системе, так как это опция конфигурации.

939
derfred

Для 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()

Для Python 3.3 и 3.4 используйте:

from importlib.machinery import SourceFileLoader

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

(Хотя это не рекомендуется в Python 3.4.)

Для Python 2 используйте:

import imp

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

Существуют эквивалентные вспомогательные функции для скомпилированных Python файлов и библиотек DLL.

Смотрите также http://bugs.python.org/issue21436 .

1074
Sebastian Rittau

Преимущество добавления пути к sys.path (по сравнению с использованием imp) состоит в том, что он упрощает процесс импорта нескольких модулей из одного пакета. Например:

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

Похоже, вы не хотите специально импортировать файл конфигурации (в котором есть множество побочных эффектов и дополнительных сложностей), вы просто хотите запустить его и иметь доступ к полученному пространству имен. Стандартная библиотека предоставляет API специально для этого в виде runpy.run_path :

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

Этот интерфейс доступен в Python 2.7 и Python 3.2+

20
ncoghlan

Вы также можете сделать что-то вроде этого и добавить каталог, в котором находится файл конфигурации, к пути загрузки Python, а затем просто выполнить обычный импорт, предполагая, что вы заранее знаете имя файла, в этот случай "конфиг".

Грязно, но это работает.

configfile = '~/config.py'

import os
import sys

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

import config
19
ctcherry

Вы можете использовать

load_source(module_name, path_to_file) 

метод из модуль imp .

16
zuber

Если ваш модуль верхнего уровня не является файлом, но упакован как каталог с помощью __init__.py, то принятое решение почти работает, но не совсем. В Python 3.5+ необходим следующий код (обратите внимание на добавленную строку, которая начинается с '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)

Без этой строки при выполнении exec_module он пытается привязать относительный импорт в вашем верхнем уровне __init__.py к имени модуля верхнего уровня - в данном случае "mymodule". Но "mymodule" еще не загружен, поэтому вы получите ошибку "SystemError: Родительский модуль" mymodule "не загружен, не может выполнить относительный импорт". Поэтому вам нужно привязать имя, прежде чем загружать его. Причиной этого является фундаментальный инвариант системы относительного импорта: "Инвариантное удержание заключается в том, что если у вас есть sys.modules ['spam'] и sys.modules ['spam.foo'] (как вы сделали бы после вышеупомянутого импорта ), последний должен отображаться как атрибут foo первого " как обсуждено здесь .

16
Sam Grondahl

Я придумал слегка измененную версию замечательный ответ @ SebastianRitta (для Python> 3.4, я думаю), которая позволит вам загружать файл с любым расширением в качестве модуля используя spec_from_loader вместо 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)

Преимущество кодирования пути в явном SourceFileLoader заключается в том, что machinery не будет пытаться определить тип файла по расширению. Это означает, что вы можете загрузить что-то вроде файла .txt, используя этот метод, но вы не можете сделать это с spec_from_file_location без указания загрузчика, потому что .txt отсутствует в importlib.machinery.SOURCE_SUFFIXES .

13
Mad Physicist

Чтобы импортировать ваш модуль, вам нужно добавить его каталог в переменную окружения, временно или постоянно.

Временно

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

Постоянно

Добавьте следующую строку в ваш файл .bashrc (в linux) и исключительный код source ~/.bashrc в терминале:

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

Кредит/Источник: saarrrr , еще один вопрос обмена стека

12
Miladiouss

Вы имеете в виду загрузку или импорт?

Вы можете манипулировать списком sys.path, указывать путь к вашему модулю, а затем импортировать ваш модуль. Например, дан модуль на:

/foo/bar.py

Вы могли бы сделать:

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

Вот код, который работает во всех версиях Python, начиная с 2.7-3.5 и, возможно, даже в других.

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

Я проверял это. Это может быть некрасиво, но пока единственный, который работает во всех версиях.

12
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

Я полагаю, что вы можете использовать imp.find_module() и imp.load_module() для загрузки указанного модуля. Вам нужно будет разделить имя модуля по пути, то есть, если вы хотите загрузить /home/mypath/mymodule.py, вам нужно сделать:

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

... но это должно сделать работу.

8
Matt

Создать python модуль test.py

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

Создать python модуль test_check.py

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

Мы можем импортировать импортированный модуль из модуля.

3
abhimanyu

Вы можете использовать модуль pkgutil (в частности, метод walk_packages ), чтобы получить список пакетов в текущем каталоге. Оттуда тривиально использовать механизм importlib для импорта модулей, которые вы хотите:

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

Это должно работать

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

Я не говорю, что это лучше, но для полноты картины я хотел бы предложить функцию exec , доступную в python 2 и 3. exec позволяет вам выполнить произвольный код либо в глобальной области, либо во внутренней области, представленной в виде словаря.

Например, если у вас есть модуль, хранящийся в "/path/to/module "с функцией foo(), вы можете запустить его, выполнив следующие действия:

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

Это делает более явным то, что вы загружаете код динамически, и дает вам некоторую дополнительную мощность, такую ​​как возможность предоставления пользовательских встроенных функций.

И если для вас важен доступ через атрибуты, а не ключи, вы можете разработать собственный класс dict для глобалов, который обеспечивает такой доступ, например:

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

Эта область Python 3.4 кажется чрезвычайно сложной для понимания! Однако с небольшим количеством взлома, используя код от Криса Кэллоуэя как начало, мне удалось заставить кое-что работать. Вот основная функция.

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

Похоже, что используются не устаревшие модули из Python 3.4. Я не притворяюсь, что понимаю почему, но, похоже, это работает изнутри программы. Я обнаружил, что решение Криса работает в командной строке, но не внутри программы.

3
Redlegjed

Чтобы импортировать модуль из заданного имени файла, вы можете временно расширить путь и восстановить системный путь в блоке 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
3
Peter Zhu

Импорт модулей пакета во время выполнения (рецепт 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

В Linux работает добавление символической ссылки в каталог, в котором находится скрипт python.

то есть:

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

python создаст /absolute/path/to/script/module.pyc и обновит его, если вы измените содержимое /absolute/path/to/module/module.py

затем включите следующее в mypythonscript.py

from module import *
2
user2760152

Я сделал пакет, который использует imp для вас. Я называю это import_file, и вот как это используется:

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

Вы можете получить его по адресу:

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

или в

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

2
ubershmekel

довольно простой способ: предположим, что вы хотите импортировать файл с относительным путем ../../MyLibs/pyfunc.py


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

Но если вы сделаете это без охраны, вы, наконец, сможете пройти очень длинный путь

1
Andrei Keino

Простое решение с использованием importlib вместо пакета imp (протестировано для Python 2.7, хотя должно работать и для 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")

Теперь вы можете напрямую использовать пространство имен импортируемого модуля, например так:

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

Преимущество этого решения в том, что нам даже не нужно знать фактическое имя модуля, который мы хотели бы импортировать, чтобы использовать его в нашем коде. Это полезно, например в случае, если путь модуля является настраиваемым аргументом.

1
Ataxias

Добавив это в список ответов, я не смог найти ничего, что сработало. Это позволит импортировать скомпилированные (pyd) python модули в 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

Этот ответ является дополнением к ответу Себастьяна Риттау, отвечающему на комментарий: "а что, если у вас нет названия модуля?" Это быстрый и грязный способ получения вероятного имени модуля python по имени файла - он просто перемещается вверх по дереву, пока не находит каталог без файла __init__.py, а затем превращает его обратно в имя файла. Для Python 3.4+ (использует pathlib), что имеет смысл, поскольку пользователи Py2 могут использовать "imp" или другие способы выполнения относительного импорта:

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

Безусловно, существуют возможности для улучшения, и необязательные файлы __init__.py могут потребовать других изменений, но если у вас есть __init__.py в целом, это поможет.

0
Michael Scott Cuthbert