Answers:
对于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具有等效的便捷功能。
__import__
。
imp.load_source
仅设置.__name__
返回模块的。它不会影响加载。
imp.load_source()
确定在sys.modules
字典中创建的新条目的键,因此第一个参数确实会影响加载。
imp
自版本3.4起不推荐使用该模块:该imp
软件包暂待弃用,而推荐使用importlib
。
(通过使用imp)向sys.path添加路径的好处是,当从单个包中导入多个模块时,它可以简化操作。例如:
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()
,但是我会在末尾添加a ,但前提是假设导入的代码在使用时不会尝试导入更多模块。
如果您的顶级模块不是文件,而是与__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,另一个stackexchange 问题
听起来您似乎不想专门导入配置文件(它具有很多副作用和其他复杂性),您只想运行它并能够访问生成的名称空间。标准库以runpy.run_path的形式专门提供了一个API :
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之前和之后有2种不同的方式。在那种情况下,我想编写自己的通用函数,而不是即时检查版本。是的,也许这段代码没有受到很好的错误保护,但是它显示了一个主意(这是os.chdir(),我对此还没有了解),可以在此基础上编写更好的代码。因此+1。
我想出了@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
则无法进行加载,因为not in中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 3.4的这一领域似乎很难理解!但是,通过使用Chris Calloway的代码进行了一些黑客操作,我设法使某些东西起作用。这是基本功能。
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)
这应该工作
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
/absolute/path/to/script/module.pyc
如果您更改python 的内容,python将会创建并更新它/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
as testlib
,testlib.blabla.py
as 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
and lower]要求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)上进行了测试,但是根据项目的大小,它可能会显得过大。
将其添加到答案列表中,因为我找不到任何有效的方法。这将允许导入3.4中的已编译(pyd)python模块:
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()
这个答案是塞巴斯蒂安·里陶(Sebastian Rittau)对评论的回答的补充:“但是,如果您没有模块名怎么办?” 这是一种在给定文件名的情况下获取可能的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 internals):
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()