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

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

Хороший и простой вопрос - и полезные ответы, но они заставляют меня задуматься о том, что случилось с мантрой python «Есть способ одиночевидный», чтобы сделать это .. Это не похоже на что-то вроде единственного или простого и очевидного ответа на него. Выглядит до смешного хакерским и зависящим от версии для такой фундаментальной операции (и в новых версиях он выглядит еще более раздутым ...).

inger 06.12.2019 15:08

@inger что произошло с мантрой питона «Есть один очевидный способ» сделать это [...] [не] единым или простым и очевидным ответом на него [...] смехотворно хакерским [...] более раздутым в новых версии Добро пожаловать в ужасный мир управления пакетами Python. Python import, virtualenv, pip, setuptools и многое другое следует выбросить и заменить рабочим кодом. Я просто попытался разобраться с virtualenv или это был pipenv, и мне пришлось работать с эквивалентом руководства по Jumbo Jet. То, как это изобретение преподносится как Решение проблемы депрессии, полностью ускользает от меня.

John Frazer 26.06.2020 23:59

соответствующий XKCD xkcd.com/1987

John Frazer 27.06.2020 00:08

@JohnFrazer усугубляет ситуацию из-за постоянного нытья людей, которые не удосужились прочитать 2 абзаца документации. Ваш XKCD на самом деле не имеет значения, поскольку он показывает, чего могут достичь эти люди, пытаясь что-то сделать, пока что-то не сработает. Кроме того, то, что появился новый способ, не означает, что теперь есть «два очевидных пути». Старый способ очевиден для одних случаев, новый способ упрощает использование в других. Вот что происходит, когда вы действительно заботитесь о DevX.

Błażej Michalik 02.12.2020 03:13

И подумайте, что Java или даже PHP (в наши дни) имеют ясный и простой способ разбивать вещи на пакеты / пространства имен и повторно использовать его. Удивительно видеть такую ​​боль в Python, который принял простоту во всех остальных аспектах.

Alex 27.01.2021 10:46
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1 307
5
1 041 165
32
Перейти к ответу Данный вопрос помечен как решенный

Ответы 32

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

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

... но на этом работа должна быть выполнена.

Ответ принят как подходящий

Для 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.

Если бы я знал пространство имен - «module.name» - я бы уже использовал __import__.

Sridhar Ratnakumar 11.08.2009 01:54

@SridharRatnakumar значение первого аргумента imp.load_source устанавливает только .__name__ возвращаемого модуля. это не влияет на загрузку.

Dan D. 14.12.2011 08:51

@DanD. - первый аргумент imp.load_source() определяет ключ новой записи, созданной в словаре sys.modules, поэтому первый аргумент действительно влияет на загрузку.

Brandon Rhodes 21.04.2013 20:32

Есть ли идея, что это репликация: "" import module.name as foo "", если ваш рабочий каталог был / path / to ?? Иначе, что здесь foo ??

capybaralet 27.02.2015 04:53

См. Новое (за декабрь 2015 г.) сообщение в разделе «Обсуждение ошибки» (bugs.python.org/issue21436#msg255901): появился третий новый способ загрузки модуля в Python 3.5 длиной в три строки!

d9k 05.12.2015 21:39

Я не вижу, что SourceFileLoader устарел в документации 3.4+.

Ryne Everett 09.01.2016 23:21

SourceFileLoader не является устаревшим, но SourceFileLoader.load_module () устарел.

Sebastian Rittau 18.01.2016 16:11

Несмотря на использование в вопросе «импорта», вы, вероятно, захотите использовать runpy.run_path для выполнения кода Python в качестве формата конфигурации, а не динамически манипулировать системой импорта.

ncoghlan 20.05.2016 09:56

@AXO и многое другое, когда возникает вопрос, почему такой простой и простой элемент, как этот имеет, может быть таким сложным. Его нет на многих других языках.

rocky 22.05.2016 20:04

Если вам нужна версия кода, которая работает во всех версиях Python, проверьте stackoverflow.com/a/37611448/99834

sorin 03.06.2016 13:05

Я использую Python 3.5.2, и я обнаружил, что Только работает, если расширение файла .py

Paolo Celati 09.07.2016 09:01

@Paolo Celati В Python 3.5+ Вы должны использовать importlib.import_module (имя_модуля). Некоторым это нравится. sys, path.append (путь_к_файлу) module = importlib.import_module (имя_модуля)

ZigZag 09.09.2016 12:06

могу я узнать, почему здесь не упоминается importlib.import_module?

Mahesha999 26.09.2016 16:13

@ Mahesha999 Потому что importlib.import_module () не позволяет вам импортировать модули по имени файла, о чем и был исходный вопрос.

Sebastian Rittau 28.09.2016 15:50

Для Python 3.5+, если /path/to/file.py неявно импортирует родственника (например, import bar для импорта /path/to/bar.py), решение выдает ModuleNotFoundError: No module named 'bar'. Как это исправить?

Pedro Cattori 24.01.2017 21:22

^ В итоге я спросил об этом в отдельном вопросе StackOverflow: stackoverflow.com/q/41861427/1490091

Pedro Cattori 26.01.2017 00:28

importlib.util.spec_from_file_location не будет импортировать файлы, которые не заканчиваются на .py = (

AlexLordThorsen 07.06.2017 05:22

Я использую python 3.6.3 на Sierra 10.12.6 и использую вариант 1 (для python 3.5+). Код работает, но когда я запускаю строку foo.MyClass(), я получаю сообщение об ошибке AttributeError: module 'myFileName' has no attribute 'MyClass', где myFileName - это имя файла python, который я передаю первому аргументу importlib.util.spec_from_file_location("module.name", "/path/to/file.py"). Тем не менее, когда я закомментировал строку foo.MyClass(), сценарий без проблем выполняет импортированный сценарий. Не могли бы кто-нибудь объяснить, что делает foo.MyClass() в предложенном коде?

Cole Robertson 23.11.2017 16:26

@ColeRobertson Эта строка - всего лишь пример, показывающий, что вам нужно префикс любого доступа к модулю с помощью foo. (или как вы называете эту переменную).

Sebastian Rittau 11.12.2017 16:28

Упоминалось, что для Python 2 вместо lib следует использовать importlib, но я не вижу примера использования importlib для импорта модуля по пути. У кого-нибудь есть такой пример?

JacksonHaenchen 15.12.2017 21:57

Этот верхний безопасен? Это кажется слишком близким к тому, чтобы просто «выполнить» все, что вам скажет пользователь. Разве не было бы безопаснее добавить каталог в sys.path, а затем запросить конкретный модуль, который вам нужен?

setholopolus 30.01.2018 21:56

@setholopolus Ничто из этого не является безопасным, если вы используете ненадежный пользовательский ввод.

Sebastian Rittau 01.02.2018 18:31

@SebastianRittau Думаю, вы правы, потому что даже если вы импортировали конкретный модуль по имени, они могли бы заменить его своим собственным модулем с тем же именем.

setholopolus 01.02.2018 22:26

@SebastianRittau Тогда какой в ​​настоящее время лучший способ для python 3.4?

Nathan 09.05.2018 05:35

Этот почти работал у меня, но когда я импортирую модуль, структурированный как каталог с _в этом_.py, мне нужна была дополнительная строка. Смотрите мой ответ ниже - надеюсь, это кому-то поможет!

Sam Grondahl 17.05.2018 18:24

Как упоминал @SamGrondahl, они не работают, если у модуля есть относительный импорт. Его отвечать предоставляет решение для python 3.5+: есть ли подобное решение для python 2.7?

mforbes 16.07.2018 04:10

Следует ли spec.loader.exec_module(foo) также гарантировать, что сценарий полностью запущен? У меня есть настройка, в которой я импортирую список переменных (и намеренно не класс), которые должны быть действительными и активными в сценарии, из которого я его вызываю. Однако, в отличие от обычного оператора import, мои переменные нельзя вызывать в дальнейшем.

Lena 18.06.2019 12:25

@Lena Должно быть, и в моем коротком тесте так и было.

Sebastian Rittau 19.06.2019 13:24

Остерегайтесь точек в имени файла, потому что последняя версия модуля python importlib все еще не может обрабатывать имена файлов модулей с точками: bugs.python.org/issue38000

Andry 07.09.2019 22:42

Интересно, как код становится ДЛИННЕ и длиннее с каждой новой версией Python. Не уверен, что это действительно «питонический способ» разработки языка программирования: / (то же самое для других вещей, таких как print () и т. д.)

Marcin Wojnarski 03.10.2019 19:33

Python 2.7: TypeError: load_module () принимает ровно 4 аргумента

Shai Alon 10.11.2019 18:54

Если импортированный файл содержит какой-либо относительный импорт, эти решения не пройдут ImportError: attempted relative import with no known parent package

Marco Castanho 05.12.2019 19:18

module.name - это тот модуль, с которого я запускаю?

Gulzar 20.01.2020 13:03

Использование описанного метода v3.5 + приводит к ошибкам травления. Ответ, связанный выше @mforbes здесь, добавляет дополнительный шаг, который, как представляется, исправляет это: sys.modules[spec.name] = foo

drootang 03.03.2020 15:40

Они что, не в своем уме создают 3 разных способа для одного и того же в этих разных языковых версиях ???

Christoph90 03.07.2020 14:22

Что такое module.name ?? Я импортирую файл или что-то из файла. У него нет пространства имен.

Myridium 27.08.2020 06:42

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

load_source(module_name, path_to_file) 

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

... и imp.load_dynamic(module_name, path_to_file) для DLL

HEKTO 16.12.2015 22:03

предупреждает, что черт возьми устарел.

t1m0 06.04.2016 21:11

Импортировать модули пакета во время выполнения (рецепт 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, а затем просто выполнить обычный импорт, если вы заранее знаете имя файла, в данном случае «config».

Беспорядочно, но это работает.

configfile = '~/config.py'

import os
import sys

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

import config

Это не динамично.

Shai Alon 10.11.2019 19:10

Я пробовал: config_file = 'setup-for-chats', setup_file = get_setup_file (config_file + ".py"), sys.path.append (os.path.dirname (os.path.expanduser (setup_fil‌ e))), import config_file >> "ImportError: Нет модуля с именем config_file"

Shai Alon 10.11.2019 19:17

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

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

/foo/bar.py

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

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

@Wheat Почему sys.path [0: 0] вместо sys.path [0]?

user618677 09.01.2012 10:56

B / c sys.path [0] = xy перезаписывает первый элемент пути, в то время как path [0: 0] = xy эквивалентен path.insert (0, xy)

dom0 15.11.2012 18:16

хм, у меня path.insert сработал, а вот трюк [0: 0] - нет.

jsh 30.09.2013 07:18

sys.path[0:0] = ['/foo']

Kevin Edwards 01.04.2015 20:00

Explicit is better than implicit. Так почему бы не sys.path.insert(0, ...) вместо sys.path[0:0]?

winklerrr 08.05.2019 14:54

@ dom0 Тогда просто переходи с sys.path.append(...). Понятнее.

Guimoute 15.11.2019 13:05

вы можете сделать это с помощью __ import __ и chdir

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 Exception as e:
        raise ImportError(e)
    return module_obj


import_file('/home/somebody/somemodule.py')

Зачем писать 14 строк кода с ошибками, если это уже решено стандартной библиотекой? Вы не выполнили проверку на ошибки в формате или содержимом full_path_to_module или других операций; а использование всеобъемлющего предложения except: редко бывает хорошей идеей.

Chris Johnson 07.06.2013 23:17

Вы должны использовать здесь больше «попробуй наконец». Например. save_cwd = os.getcwd()try: …finally: os.chdir(save_cwd)

kay 21.09.2014 05:33

@ChrisJohnson this is already addressed by the standard library да, но у python неприятная привычка не быть обратно совместимой ... поскольку проверенный ответ говорит, что есть 2 разных способа до и после 3.3. В таком случае я бы предпочел написать свою универсальную функцию, чем проверять версию на лету. И да, возможно, этот код не слишком хорошо защищен от ошибок, но он показывает идею (это os.chdir (), я не думал об этом), на основе которой я могу написать лучший код. Следовательно, +1.

Sushi271 15.05.2015 13:27

Было бы здорово, если бы это действительно вернуло модуль.

Pithikos 30.07.2020 17:41

Преимущество добавления пути к 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

Как мы можем использовать sys.path.append, чтобы указать на один файл Python вместо каталога?

Phani 13.01.2014 21:46

@ Дэрил Спитцер: Как это сделать для одного файла Python

Srivatsan 06.03.2014 20:20

Как мы используем это для одного файла Python? И почему ты 7 лет игнорируешь нас?

runw 06.03.2015 01:59

:-) Возможно, ваш вопрос лучше подошел бы как вопрос StackOverflow, а не как комментарий к ответу.

Daryl Spitzer 06.03.2015 03:12

Для всех людей, которые пытались включить файл в свой путь ... по определению «путь оболочки - это список каталогов, разделенных двоеточиями». Я относительно новичок в python, но путь python также следует принципу дизайна unix из того, что я видел. Пожалуйста, поправьте меня, если я ошибаюсь.

m33k 15.04.2015 08:37

Путь python может содержать zip-архивы, «яйца» (сложный вид zip-архивов) и т. д. Из них можно импортировать модули. Таким образом, элементы пути действительно являются контейнеры файлов, но это не обязательно каталоги.

alexis 01.05.2015 00:21

Остерегайтесь того факта, что Python кэширует операторы импорта. В редком случае, когда у вас есть две разные папки, совместно использующие одно имя класса (classX), подход к добавлению пути к sys.path, импорту classX, удалению пути и повторению для новых путей не сработает. Python всегда будет загружать класс из своего кеша по первому пути. В моем случае я стремился создать систему плагинов, в которой все плагины реализуют определенный classX. В итоге я использовал SourceFileLoader, обратите внимание, что его Устаревшая является спорным.

ComFreek 03.07.2015 20:18

Я предпочитаю это решение принятому, потому что оно все еще работает на Python 3.6 и потому, что для него требуется всего 2 простые строки кода, чтобы можно было найти любое количество модулей в другом каталоге сайта. Наша конкретная ситуация была на веб-сервере, где централизованно установлено только несколько основных пакетов, и таким образом сценарии CGI, созданные пользователями, могут быть импортированы из их каталога пользовательских сайтов. Спасибо!

ybull 08.03.2018 01:07

В моем случае импортированный файл имел другой (транзитивный) импорт относительного пути; объединение принятого ответа (importlib) с этим сработало для меня.

Janaka Bandara 29.03.2019 09:07

Обратите внимание, что этот подход позволяет импортированному модулю импортировать другие модули из того же каталога, что часто делают модули, а подход принятого ответа - нет (по крайней мере, в 3.7). importlib.import_module(mod_name) можно использовать вместо явного импорта здесь, если имя модуля неизвестно во время выполнения, я бы добавил sys.path.pop() в конце, однако, предполагая, что импортированный код не пытается импортировать больше модулей по мере его использования.

Eli_B 07.05.2019 00:45

Этот должен быть на высоте!

Soufiane Chami 21.07.2019 16:23

Я сделал для вас пакет, который использует 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/

os.chdir? (минимальное количество символов для подтверждения комментария).

ychaouche 14.10.2012 14:46

Я потратил весь день на устранение ошибки импорта в exe-файле, созданном pyinstaller. В конце концов, это единственное, что у меня сработало. Большое вам спасибо за это!

frakman1 30.11.2018 01:12

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

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)

Более общий способ вырезания удлинителя: name, ext = os.path.splitext(os.path.basename(infile)). Ваш метод работает, потому что предыдущее ограничение на расширение .py. Кроме того, вам, вероятно, следует импортировать модуль в какую-либо запись переменной / словаря.

ReneSac 06.12.2012 17:16

Вы можете использовать модуль 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, работает.

то есть:

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 *

Это хак, который я использовал, и он вызвал у меня некоторые проблемы. Одним из наиболее болезненных моментов было то, что у IDEA есть проблема, когда он не берет измененный код из ссылки, но все же пытается сохранить то, что, по его мнению, существует. Состояние гонки, когда сохраняется последний, кто сохраняет ... Из-за этого я потерял приличный объем работы.

Gripp 17.06.2015 02:23

@Gripp не уверен, понимаю ли я вашу проблему, но я часто (почти исключительно) редактирую свои скрипты на удаленном сервере со своего рабочего стола через SFTP с таким клиентом, как CyberDuck, и в этом случае также плохая идея пытаться и отредактируйте файл, связанный с символической ссылкой, вместо этого гораздо безопаснее редактировать исходный файл. Вы можете выявить некоторые из этих проблем, используя git и проверяя свой git status, чтобы убедиться, что ваши изменения в скрипте действительно возвращаются в исходный документ и не теряются в эфире.

user5359531 01.08.2017 22:39

Думаю, лучший способ - из официальной документации (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()

Это решение не позволяет указать путь, о котором спрашивает вопрос.

Micah Smith 11.04.2018 20:20

Эта область 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

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

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

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

Мне нравится этот метод, но когда я получаю результат run_path, это словарь, к которому я не могу получить доступ?

Stephen Ellwood 11.09.2018 12:00

Что вы имеете в виду, говоря «нет доступа»? Вы не можете импортировать из него (поэтому это хороший вариант, когда доступ в стиле импорта на самом деле не требуется), но содержимое должно быть доступно через обычный dict API (result[name], result.get('name', default_value) и т. д.)

ncoghlan 13.09.2018 06:16

Этот ответ сильно недооценен. Это очень коротко и просто! Еще лучше, если вам нужно правильное пространство имен модуля, вы можете сделать что-то вроде from runpy import run_path; from argparse import Namespace; mod = Namespace(**run_path('path/to/file.py'))

RuRo 19.03.2020 00:26

Привет, Ник. В PEP 338 вы ввели только функцию runpy.run_module и сказали, что python -m module_name теперь делегирует ей полномочия. 1. Вы писали аналогичный PEP для функции runpy.run_path? 2. Делегирует ли python file_path.py теперь runpy.run_path?

Maggyero 16.09.2020 00:50

Кроме того, я только что открыл открытый вопрос здесь о вашем PEP 366. Мне очень интересно ваше мнение по этому поводу.

Maggyero 16.09.2020 00:53

@Maggyero Командная строка никогда не проходит через runpy.run_path, но если заданный путь является каталогом или zip-файлом, он в конечном итоге делегирует runpy.run_module для выполнения __main__. Дублированная логика для "Это сценарий, каталог или zip-файл?" недостаточно сложен, чтобы его стоило делегировать коду Python.

ncoghlan 22.09.2020 10:39

Спасибо, я не знал об этом. В CPython происходит ли делегирование runpy.run_module для данного имени модуля (python -m name) точно здесь, а для данного каталога или пути к zip-файлу (python path) происходит точно здесь?

Maggyero 22.09.2020 12:30

Также, глядя на выполнение функции C pymain_run_module, кажется, что CPython делегирует функцию Python runpy._run_module_as_main вместо runpy.run_module - хотя, если я правильно понял, единственная разница в том, что первая функция выполняет код во встроенной среде __main__ ( см. здесь), а вторая функция выполняет его в новой среде?

Maggyero 22.09.2020 12:33

@Maggyero Ага, это единственная разница. Первоначально он использовал публичную функцию, но оказалось, что она плохо взаимодействует с опцией интерпретатора -i (которая сбрасывает вас в интерактивную оболочку в исходном модуле __main__, поэтому запуск -m в новом модуле был неудобным)

ncoghlan 26.10.2020 10:10

Вот код, который работает во всех версиях 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())

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

Этот ответ работал у меня там, где load_source не работал, потому что он импортирует скрипт и предоставляет скрипту доступ к модулям и глобальным объектам во время импорта.

Klik 22.11.2017 22:13

Я придумал слегка измененную версию @ Замечательный ответ Себастьяна Риттау (думаю, для 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 без указания загрузчика, потому что .txt не находится в importlib.machinery.SOURCE_SUFFIXES.

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

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


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

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

Если ваш модуль верхнего уровня не является файлом, а упакован как каталог с __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 первого "как обсуждалось здесь.

Большое спасибо! Этот метод позволяет относительный импорт между подмодулями. Большой!

tebanep 10.10.2019 17:09

Этот ответ соответствует документации здесь: docs.python.org/3/library/….

Tim Ludwinski 09.12.2019 19:08

а что такое mymodule?

Gulzar 20.01.2020 13:02

@Gulzar, это любое имя, которое вы хотите дать своему модулю, чтобы потом вы могли сделать это: "from mymodule import myclass"

Idodo 17.02.2020 01:44

Итак ... /path/to/your/module/ на самом деле /path/to/your/PACKAGE/? а под mymodule вы имеете ввиду myfile.py?

Gulzar 17.02.2020 10:03

Что такое mymodule по сравнению с /path/to/your/module/__init__.py?

IAbstract 20.05.2020 19:24

Хотя это и нетрадиционно, но если ваша точка входа в пакет отличается от __init__.py, вы все равно можете импортировать ее как пакет. Включите spec.submodule_search_locations = [os.path.dirname(MODULE_PATH)] после создания спецификации. Вы также можете рассматривать __init__.py как не-пакет (например, одиночный модуль), задав для этого значения None.

Azmisov 05.11.2020 23:32

Простое решение с использованием 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)

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

Таким образом вы модифицируете sys.path, что подходит не для всех вариантов использования.

bgusach 19.07.2018 17:26

@bgusach Это может быть правдой, но в некоторых случаях это также желательно (добавление пути к sys.path упрощает импорт более чем одного модуля из одного пакета). Во всяком случае, если это нежелательно, можно сразу после этого сделать sys.path.pop().

Ataxias 20.07.2018 19:38

Этот ответ является дополнением к ответу Себастьяна Риттау на комментарий: «а что, если у вас нет имени модуля?» Это быстрый и грязный способ получить вероятное имя модуля 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 в целом, это поможет.

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

Временно

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

Постоянно

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

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

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

Это временное решение - отличный ответ, если вы хотите запустить проект в блокноте jupyter в другом месте.

fordy 16.11.2018 20:20

Но ... это опасно вмешиваться в путь

Shai Alon 10.11.2019 18:56

@ShaiAlon Вы добавляете пути, поэтому нет никакой опасности, кроме передачи кодов с одного компьютера на другой, пути могут быть перепутаны. Итак, для разработки пакетов я импортирую только локальные пакеты. Кроме того, имена пакетов должны быть уникальными. Если вы беспокоитесь, воспользуйтесь временным решением.

Miladiouss 13.11.2019 03:11

Спасибо. Мне нравятся короткие, чистые, лаконичные ответы.

DimiDak 25.08.2020 15:54

Создать модуль 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

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

Я написал свою собственную глобальную и переносимую функцию импорта, основанную на модуле importlib, для:

  • Уметь импортировать как модуль как подмодуль, так и импортировать содержимое модуля в родительский модуль (или в глобальные объекты, если родительский модуль отсутствует).
  • Уметь импортировать модули с точками в имени файла.
  • Уметь импортировать модули с любым расширением.
  • Уметь использовать отдельное имя для подмодуля вместо имени файла без расширения, которое используется по умолчанию.
  • Уметь определять порядок импорта на основе ранее импортированного модуля, а не зависеть от sys.path или любого хранилища путей поиска.

Структура каталогов примеров:

<root>
 |
 +- test.py
 |
 +- testlib.py
 |
 +- /std1
 |   |
 |   +- testlib.std1.py
 |
 +- /std2
 |   |
 |   +- testlib.std2.py
 |
 +- /std3
     |
     +- testlib.std3.py

Зависимость и порядок включения:

test.py
  -> testlib.py
    -> testlib.std1.py
      -> testlib.std2.py
    -> testlib.std3.py 

Выполнение:

Магазин последних изменений: https://sourceforge.net/p/tacklelib/tacklelib/HEAD/tree/trunk/python/tacklelib/tacklelib.py

test.py:

import os, sys, inspect, copy

SOURCE_FILE = os.path.abspath(inspect.getsourcefile(lambda:0)).replace('\','/')
SOURCE_DIR = os.path.dirname(SOURCE_FILE)

print("test::SOURCE_FILE: ", SOURCE_FILE)

# portable import to the global space
sys.path.append(TACKLELIB_ROOT) # TACKLELIB_ROOT - path to the library directory
import tacklelib as tkl

tkl.tkl_init(tkl)

# cleanup
del tkl # must be instead of `tkl = None`, otherwise the variable would be still persist
sys.path.pop()

tkl_import_module(SOURCE_DIR, 'testlib.py')

print(globals().keys())

testlib.base_test()
testlib.testlib_std1.std1_test()
testlib.testlib_std1.testlib_std2.std2_test()
#testlib.testlib.std3.std3_test()                             # does not reachable directly ...
getattr(globals()['testlib'], 'testlib.std3').std3_test()     # ... but reachable through the `globals` + `getattr`

tkl_import_module(SOURCE_DIR, 'testlib.py', '.')

print(globals().keys())

base_test()
testlib_std1.std1_test()
testlib_std1.testlib_std2.std2_test()
#testlib.std3.std3_test()                                     # does not reachable directly ...
globals()['testlib.std3'].std3_test()                         # ... but reachable through the `globals` + `getattr`

testlib.py:

# optional for 3.4.x and higher
#import os, inspect
#
#SOURCE_FILE = os.path.abspath(inspect.getsourcefile(lambda:0)).replace('\','/')
#SOURCE_DIR = os.path.dirname(SOURCE_FILE)

print("1 testlib::SOURCE_FILE: ", SOURCE_FILE)

tkl_import_module(SOURCE_DIR + '/std1', 'testlib.std1.py', 'testlib_std1')

# SOURCE_DIR is restored here
print("2 testlib::SOURCE_FILE: ", SOURCE_FILE)

tkl_import_module(SOURCE_DIR + '/std3', 'testlib.std3.py')

print("3 testlib::SOURCE_FILE: ", SOURCE_FILE)

def base_test():
  print('base_test')

testlib.std1.py:

# optional for 3.4.x and higher
#import os, inspect
#
#SOURCE_FILE = os.path.abspath(inspect.getsourcefile(lambda:0)).replace('\','/')
#SOURCE_DIR = os.path.dirname(SOURCE_FILE)

print("testlib.std1::SOURCE_FILE: ", SOURCE_FILE)

tkl_import_module(SOURCE_DIR + '/../std2', 'testlib.std2.py', 'testlib_std2')

def std1_test():
  print('std1_test')

testlib.std2.py:

# optional for 3.4.x and higher
#import os, inspect
#
#SOURCE_FILE = os.path.abspath(inspect.getsourcefile(lambda:0)).replace('\','/')
#SOURCE_DIR = os.path.dirname(SOURCE_FILE)

print("testlib.std2::SOURCE_FILE: ", SOURCE_FILE)

def std2_test():
  print('std2_test')

testlib.std3.py:

# optional for 3.4.x and higher
#import os, inspect
#
#SOURCE_FILE = os.path.abspath(inspect.getsourcefile(lambda:0)).replace('\','/')
#SOURCE_DIR = os.path.dirname(SOURCE_FILE)

print("testlib.std3::SOURCE_FILE: ", SOURCE_FILE)

def std3_test():
  print('std3_test')

Выход (3.7.4):

test::SOURCE_FILE:  <root>/test01/test.py
import : <root>/test01/testlib.py as testlib -> []
1 testlib::SOURCE_FILE:  <root>/test01/testlib.py
import : <root>/test01/std1/testlib.std1.py as testlib_std1 -> ['testlib']
import : <root>/test01/std1/../std2/testlib.std2.py as testlib_std2 -> ['testlib', 'testlib_std1']
testlib.std2::SOURCE_FILE:  <root>/test01/std1/../std2/testlib.std2.py
2 testlib::SOURCE_FILE:  <root>/test01/testlib.py
import : <root>/test01/std3/testlib.std3.py as testlib.std3 -> ['testlib']
testlib.std3::SOURCE_FILE:  <root>/test01/std3/testlib.std3.py
3 testlib::SOURCE_FILE:  <root>/test01/testlib.py
dict_keys(['__name__', '__doc__', '__package__', '__loader__', '__spec__', '__annotations__', '__builtins__', '__file__', '__cached__', 'os', 'sys', 'inspect', 'copy', 'SOURCE_FILE', 'SOURCE_DIR', 'TackleGlobalImportModuleState', 'tkl_membercopy', 'tkl_merge_module', 'tkl_get_parent_imported_module_state', 'tkl_declare_global', 'tkl_import_module', 'TackleSourceModuleState', 'tkl_source_module', 'TackleLocalImportModuleState', 'testlib'])
base_test
std1_test
std2_test
std3_test
import : <root>/test01/testlib.py as . -> []
1 testlib::SOURCE_FILE:  <root>/test01/testlib.py
import : <root>/test01/std1/testlib.std1.py as testlib_std1 -> ['testlib']
import : <root>/test01/std1/../std2/testlib.std2.py as testlib_std2 -> ['testlib', 'testlib_std1']
testlib.std2::SOURCE_FILE:  <root>/test01/std1/../std2/testlib.std2.py
2 testlib::SOURCE_FILE:  <root>/test01/testlib.py
import : <root>/test01/std3/testlib.std3.py as testlib.std3 -> ['testlib']
testlib.std3::SOURCE_FILE:  <root>/test01/std3/testlib.std3.py
3 testlib::SOURCE_FILE:  <root>/test01/testlib.py
dict_keys(['__name__', '__doc__', '__package__', '__loader__', '__spec__', '__annotations__', '__builtins__', '__file__', '__cached__', 'os', 'sys', 'inspect', 'copy', 'SOURCE_FILE', 'SOURCE_DIR', 'TackleGlobalImportModuleState', 'tkl_membercopy', 'tkl_merge_module', 'tkl_get_parent_imported_module_state', 'tkl_declare_global', 'tkl_import_module', 'TackleSourceModuleState', 'tkl_source_module', 'TackleLocalImportModuleState', 'testlib', 'testlib_std1', 'testlib.std3', 'base_test'])
base_test
std1_test
std2_test
std3_test

Протестировано на Python 3.7.4, 3.2.5, 2.7.16

Плюсы:

  • Может импортировать оба модуля как подмодуль и может импортировать содержимое модуля в родительский модуль (или в глобальные объекты, если родительский модуль отсутствует).
  • Можно импортировать модули с точками в имени файла.
  • Может импортировать любой модуль расширения из любого модуля расширения.
  • Может использовать отдельное имя для подмодуля вместо имени файла без расширения, которое используется по умолчанию (например, testlib.std.py как testlib, testlib.blabla.py как testlib_blabla и т. д.).
  • Не зависит от sys.path или от любого хранилища путей поиска.
  • Не требует сохранения / восстановления глобальных переменных, таких как SOURCE_FILE и SOURCE_DIR, между вызовами tkl_import_module.
  • [для 3.4.x и выше] Может смешивать пространства имен модулей во вложенных вызовах tkl_import_module (например, named->local->named или local->named->local и т. д.).
  • [для 3.4.x и выше] Может автоматически экспортировать глобальные переменные / функции / классы, откуда они были объявлены, во все дочерние модули, импортированные через tkl_import_module (через функцию tkl_declare_global).

Минусы:

  • [для 3.3.x и ниже] Требовать объявления tkl_import_module во всех модулях, которые обращаются к tkl_import_module (дублирование кода)

Обновление 1,2 (только для 3.4.x и выше):

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

Обновление 3:

Добавлена ​​функция tkl_source_module как аналог bash source с поддержкой защиты выполнения при импорте (реализована через слияние модулей вместо импорта).

Обновление 4:

Добавлена ​​функция tkl_declare_global для автоматического экспорта глобальной переменной модуля во все дочерние модули, где глобальная переменная модуля не отображается, поскольку не является частью дочернего модуля.

Обновление 5:

Все функции перенесены в библиотеку tacklelib, см. Ссылку выше.

Специально для этого есть упаковка:

from thesmuggler import smuggle

# À la `import weapons`
weapons = smuggle('weapons.py')

# À la `from contraband import drugs, alcohol`
drugs, alcohol = smuggle('drugs', 'alcohol', source='contraband.py')

# À la `from contraband import drugs as dope, alcohol as booze`
dope, booze = smuggle('drugs', 'alcohol', source='contraband.py')

Он протестирован во всех версиях Python (в том числе Jython и PyPy), но может оказаться излишним в зависимости от размера вашего проекта.

Если у нас есть скрипты в одном проекте, но в разных каталогах, мы можем решить эту проблему следующим способом.

В этой ситуации utils.py находится в src/main/util/

import sys
sys.path.append('./')

import src.main.util.utils
#or
from src.main.util.utils import json_converter # json_converter is example method

самый простой ИМО

Ardhi 06.06.2020 19:07

Это две мои служебные функции, использующие только pathlib. Он выводит имя модуля из пути По умолчанию он рекурсивно загружает все файлы Python из папок и заменяет в этом.py именем родительской папки. Но вы также можете указать путь и / или глобус для выбора некоторых конкретных файлов.

from pathlib import Path
from importlib.util import spec_from_file_location, module_from_spec
from typing import Optional


def get_module_from_path(path: Path, relative_to: Optional[Path] = None):
    if not relative_to:
        relative_to = Path.cwd()

    abs_path = path.absolute()
    relative_path = abs_path.relative_to(relative_to.absolute())
    if relative_path.name == "__init__.py":
        relative_path = relative_path.parent
    module_name = ".".join(relative_path.with_suffix("").parts)
    mod = module_from_spec(spec_from_file_location(module_name, path))
    return mod


def get_modules_from_folder(folder: Optional[Path] = None, glob_str: str = "*/**/*.py"):
    if not folder:
        folder = Path(".")

    mod_list = []
    for file_path in sorted(folder.glob(glob_str)):
        mod_list.append(get_module_from_path(file_path))

    return mod_list

Вот способ загрузки файлов вроде C и т. д.

from importlib.machinery import SourceFileLoader
import os

def LOAD (MODULE_PATH):
    if (MODULE_PATH [ 0 ] == "/"):
        FULL_PATH = MODULE_PATH;
    else:
        DIR_PATH = os.path.dirname (os.path.realpath (__file__))
        FULL_PATH = os.path.normpath (DIR_PATH + "/" + MODULE_PATH)

    return SourceFileLoader (FULL_PATH, FULL_PATH).load_module ()

Реализации Где:

Y = LOAD ("../Z.py")
A = LOAD ("./A.py")
D = LOAD ("./C/D.py")
A_ = LOAD ("/IMPORTS/A.py")

Y.DEF ();
A.DEF ();
D.DEF ();
A_.DEF ();

Где каждый из файлов выглядит так:

def DEF ():
    print ("A");

Я считаю, что это простой ответ: модуль = dict ()

code = """
import json 
def testhi() : 
    return json.dumps({"key" : "value"}, indent = 4 )
"""
exec(code, module)
x = module['testhi']()
print(x)

Другие вопросы по теме