24 ответов:
для 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.
преимущество добавления пути к sys.путь (через использование 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
вы также можете сделать что-то вроде этого и добавить каталог, в котором находится файл конфигурации, в путь загрузки Python, а затем просто сделать обычный импорт, предполагая, что вы знаете имя файла заранее, в этом случае "config".
сумбурно, но это работает.
configfile = '~/config.py' import os import sys sys.path.append(os.path.dirname(os.path.expanduser(configfile))) import config
можно использовать
load_source(module_name, path_to_file)метод модуль imp.
похоже, что вы не хотите специально импортировать файл конфигурации (который имеет множество побочных эффектов и дополнительных осложнений), вы просто хотите запустить его и получить доступ к результирующему пространству имен. Стандартная библиотека предоставляет API специально для этого в виде runpy.run_path:
from runpy import run_path settings = run_path("/path/to/file.py")этот интерфейс доступен в Python 2.7 и Python 3.2+
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')
Вы имеете в виду нагрузки или импортные?
вы можете управлять системой.список путей укажите путь к модулю, а затем импортируйте модуль. Например, задается модуль по адресу:
/foo/bar.pyвы могли бы сделать:
import sys sys.path[0:0] = '/foo' # puts the /foo directory at the start of your path import bar
Я считаю, что вы можете использовать
imp.find_module()иimp.load_module()для загрузки указанного модуля. Вам нужно будет разделить имя модуля от пути, т. е. если вы хотите загрузить/home/mypath/mymodule.pyнужно сделать:imp.find_module('mymodule', '/home/mypath/')...но это должно быть сделано.
вот некоторый код, который работает во всех версиях 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())Я проверял. Это может быть некрасиво, но пока это единственный, который работает во всех версиях.
Я придумал немного измененную версию @SebastianRittau замечательный ответ (для 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это оборудование не будет пытаться определить тип файла по расширению. Этот означает, что вы можете загрузить что-то вроде.txtфайл с помощью этого метода, но вы не можете сделать это сspec_from_file_locationбез указания loader, потому что.txtнеimportlib.machinery.SOURCE_SUFFIXES.
если ваш модуль верхнего уровня не является файлом, но упакован как каталог с __init__.py, тогда принятое решение почти работает, но не совсем. В Python 3.5+ необходим следующий код (обратите внимание на добавленную строку, которая начинается с 'sys.модули'):
MODULE_PATH = "/path/to/your/module/__init__.py" MODULE_NAME = "mymodule" spec = importlib.util.spec_from_file_location("mymodule", 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.модули [спам] и sys.модули['спам.foo'] (как и после вышеуказанного импорта), последний должен отображаться как атрибут foo первого"как обсуждалось здесь.
Это должно работать
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)
в этом районе в 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. Я не претендую на то, чтобы понять, почему, но это, кажется, работает внутри программы. Я обнаружил, что решение Криса работает в командной строке, но не изнутри программы.
Я не говорю, что это лучше, но для полноты картины, я хотел бы предложить
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)
чтобы импортировать модуль из заданного имени файла, вы можете временно расширить путь и восстановить системный путь в блоке 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
импорт модулей пакета во время выполнения (рецепт 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)
можно использовать
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!
в Linux добавление символической ссылки в каталог, в котором находится ваш скрипт python, работает.
ie:
ln -s /absolute/path/to/module/module.py /absolute/path/to/script/module.pypython создаст
/absolute/path/to/script/module.pycи обновит его, если вы измените содержимое/absolute/path/to/module/module.pyзатем включите следующее mypythonscript.py
from module import *
Я сделал пакет, который использует
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
или
довольно простой способ: предположим, вы хотите импортировать файл с относительным путем .. / ../MyLibs/pyfunc.py
libPath = '../../MyLibs' import sys if not libPath in sys.path: sys.path.append(libPath) import pyfunc as pfно если вы сделаете это без охраны можно, наконец, получить очень длинный путь
простое решение с помощью
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)преимущество этого решения заключается в том, что нам даже не нужно знать фактическое имя модуля, который мы хотели бы импортировать, чтобы использовать его в нашем коде. Это полезно, например, в случае, если путь модуля настраиваемый аргумент.
добавлять это в список ответов, поскольку я не мог найти ничего, что работал. Это позволит импортировать скомпилированные (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()
этот ответ является дополнением к ответу Себастьяна Риттау, отвечая на комментарий: "но что, если у вас нет имени модуля?"Это быстрый и грязный способ получить вероятное имя модуля 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В общем, это делает трюк.
самый лучший способ, я думаю, это из официальной документации (29.1. imp-доступ к внутренним элементам импорта):
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()
Comments