Як я можу завантажити модуль Python з урахуванням його повного шляху? Зауважте, що файл може знаходитися в будь-якій точці файлової системи, оскільки це варіант конфігурації.
Як я можу завантажити модуль Python з урахуванням його повного шляху? Зауважте, що файл може знаходитися в будь-якій точці файлової системи, оскільки це варіант конфігурації.
Відповіді:
Для використання 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 .
__import__
.
imp.load_source
лише .__name__
повернений модуль. це не впливає на завантаження.
imp.load_source()
визначає ключ нового запису, створеного у sys.modules
словнику, тому перший аргумент дійсно впливає на завантаження.
imp
Модуль є застарілим , починаючи з версії 3.4: imp
пакет знаходиться на розгляді Deprecation на користь importlib
.
Перевага додавання шляху до 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 замість каталогу?
importlib.import_module(mod_name)
тут можна використовувати замість явного імпорту, якщо ім'я модуля невідоме під час виконання, я б додав sys.path.pop()
в кінці кінців, хоча, припускаючи, що імпортований код не намагається імпортувати більше модулів, як він використовується.
Якщо ваш модуль верхнього рівня не є файлом, але пакується як каталог з __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 колишнього ", про який йде мова тут .
mymodule
?
/path/to/your/module/
насправді /path/to/your/PACKAGE/
? а mymodule
ти маєш на увазі myfile.py
?
Щоб імпортувати ваш модуль, вам потрібно додати його каталог до змінної середовища, тимчасово або постійно.
import sys
sys.path.append("/path/to/my/modules/")
import my_module
Додавання наступного рядка до вашого .bashrc
файлу (в Linux) та виведення source ~/.bashrc
у терміналі:
export PYTHONPATH="${PYTHONPATH}:/path/to/my/modules/"
Кредит / Джерело: saarrrr , ще одне питання обміну ставок
Це здається, що ви не хочете спеціально імпортувати файл конфігурації (який містить безліч побічних ефектів та додаткових ускладнень), ви просто хочете запустити його та мати доступ до отриманого простору імен. Стандартна бібліотека надає API спеціально для цього у вигляді runpy.run_path :
from runpy import run_path
settings = run_path("/path/to/file.py")
Цей інтерфейс доступний в Python 2.7 та Python 3.2+
result[name]
, result.get('name', default_value)
, і т.д.)
from runpy import run_path; from argparse import Namespace; mod = Namespace(**run_path('path/to/file.py'))
Ви також можете зробити щось подібне і додати каталог, у якому знаходиться файл конфігурації, на шлях завантаження Python, а потім просто виконати звичайний імпорт, якщо ви заздалегідь знаєте ім'я файлу, у цьому випадку "config".
Брудний, але це працює.
configfile = '~/config.py'
import os
import sys
sys.path.append(os.path.dirname(os.path.expanduser(configfile)))
import config
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')
except:
застереження " загальний вигляд" - це рідко корисна ідея.
save_cwd = os.getcwd()
try: …
finally: os.chdir(save_cwd)
this is already addressed by the standard library
Так, але python має неприємну звичку бути невідповідним ... як зазначено у перевіреній відповіді, існує два різних способи до та після 3.3. У такому випадку я б хотів написати власну універсальну функцію, ніж перевірити версію на льоту. І так, можливо, цей код не надто добре захищений від помилок, але він показує ідею (яка є os.chdir (), я не хоч про це), на основі якої я можу написати кращий код. Звідси +1.
Ось код, який працює у всіх версіях 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
ні, тому що вона імпортує скрипт і забезпечує доступ сценарію до модулів та глобальних мереж під час імпорту.
Я придумав трохи модифіковану версію чудової відповіді @ 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
не вказавши завантажувач, оскільки .txt
він не входить importlib.machinery.SOURCE_SUFFIXES
.
Ви маєте на увазі завантаження чи імпорт?
Ви можете маніпулювати sys.path
списком із зазначенням шляху до вашого модуля, а потім імпортувати модуль. Наприклад, заданий модуль за адресою:
/foo/bar.py
Ви можете зробити:
import sys
sys.path[0:0] = ['/foo'] # puts the /foo directory at the start of your path
import bar
sys.path[0:0] = ['/foo']
Explicit is better than implicit.
То чому б не sys.path.insert(0, ...)
замість цього sys.path[0:0]
?
Я вважаю, що ви можете використовувати imp.find_module()
та imp.load_module()
завантажити вказаний модуль. Вам потрібно буде розділити ім'я модуля від шляху, тобто, якщо ви хочете завантажити, /home/mypath/mymodule.py
вам потрібно буде зробити:
imp.find_module('mymodule', '/home/mypath/')
... але це повинно зробити роботу.
Ви можете використовувати 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!
Створіть модуль 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
Ми можемо імпортувати імпортний модуль з модуля.
Ця область 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']()
Це робить трохи більш очевидним, що ви завантажуєте код динамічно, і надає вам додаткову потужність, наприклад, можливість надання користувальницьких вбудованих файлів.
І якщо для вас важливий доступ через атрибути, замість ключів, ви можете створити призначений для глобального класу клас диктантів, який забезпечує такий доступ, наприклад:
class MyModuleClass(dict):
def __getattr__(self, name):
return self.__getitem__(name)
Щоб імпортувати модуль із заданого імені файлу, ви можете тимчасово розширити шлях і відновити системний шлях у остаточному блоці посилання:
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
Це має спрацювати
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 розширення. Крім того, вам, мабуть, слід імпортувати модуль до якоїсь записи змінної / словника.
Якщо у нас в одному проекті є сценарії, але в різних засобах каталогу, ми можемо вирішити цю проблему наступним методом.
У цій ситуації 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
Я зробив пакет, який використовує 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
або в
Імпорт модулів пакета під час виконання (рецепт 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)
В 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 *
git
і перевіривши свої дані, git status
щоб переконатися, що зміни в сценарії насправді повертають його до вихідного документа та не втрачаються в ефірі.
Я написав власну глобальну та портативну функцію імпорту на основі 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 :
Усі функції перемістилися в бібліотеку снастей, див. Посилання вище.
Є пакет , присвячений саме цьому:
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), але це може бути надмірним, залежно від розміру вашого проекту.
Додавши це до списку відповідей, оскільки я не зміг знайти нічого, що працювало. Це дозволить імпортувати складені (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
Але якщо ви зробите це без охорони, нарешті, ви можете отримати дуже довгий шлях
Просте рішення, використовуючи 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
, що не відповідає кожному випадку використання.
sys.path.pop()
Ця відповідь є доповненням до відповіді Себастьяна Ріттау на коментар: "але що робити, якщо у вас немає назви модуля?" Це швидкий і брудний спосіб отримання ймовірного імені модуля python з назвою файлу - він просто піднімається вгору по дереву, поки не знайде каталог без __init__.py
файлу, а потім перетворить його назад у ім’я файлу. Для Python 3.4+ (використовує pathlib), що має сенс, оскільки люди з Py2 можуть використовувати "імп" або інші способи здійснення відносного імпорту:
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()