How to import all submodules?
我有如下目录结构:
1 2 3 4 5 6 | | main.py | scripts |--| __init__.py | script1.py | script2.py | script3.py |
从
编辑:很抱歉我有点含糊不清。我希望在运行时导入子模块,而不在
编辑:这里有一种在运行时递归导入所有内容的方法…
(顶层包目录中
1 2 3 4 5 6 7 | import pkgutil __all__ = [] for loader, module_name, is_pkg in pkgutil.walk_packages(__path__): __all__.append(module_name) _module = loader.find_module(module_name).load_module(module_name) globals()[module_name] = _module |
这里我没有使用
也许还有更好的办法,但这是我能做的最好的办法。
原始答案(对于上下文,忽略Othwerwise。我最初误解了这个问题):
你的
1 2 3 4 | import script1 import script2 import script3 __all__ = ['script1', 'script2', 'script3'] |
您甚至可以不定义
这是基于Kolypto提供的答案,但他的答案不执行包的递归导入,而这确实执行了。虽然主要问题不需要,但我相信递归导入适用,并且在许多类似的情况下非常有用。例如,我在搜索这个主题时发现了这个问题。
这是执行子包模块导入的一种好的、干净的方法,而且应该是可移植的,并且它使用了用于python 2.7+/3.x的标准lib。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | import importlib import pkgutil def import_submodules(package, recursive=True): """ Import all submodules of a module, recursively, including subpackages :param package: package (name or actual module) :type package: str | module :rtype: dict[str, types.ModuleType] """ if isinstance(package, str): package = importlib.import_module(package) results = {} for loader, name, is_pkg in pkgutil.walk_packages(package.__path__): full_name = package.__name__ + '.' + name results[full_name] = importlib.import_module(full_name) if recursive and is_pkg: results.update(import_submodules(full_name)) return results |
用途:
1 2 3 4 5 6 | # from main.py, as per the OP's project structure import scripts import_submodules(scripts) # Alternatively, from scripts.__init__.py import_submodules(__name__) |
工作简单,允许在包内进行相对导入:
1 2 3 4 5 6 7 8 9 10 11 12 | def import_submodules(package_name): """ Import all submodules of a module, recursively :param package_name: Package name :type package_name: str :rtype: dict[types.ModuleType] """ package = sys.modules[package_name] return { name: importlib.import_module(package_name + '.' + name) for loader, name, is_pkg in pkgutil.walk_packages(package.__path__) } |
用途:
1 | __all__ = import_submodules(__name__).keys() |
虽然没有我想要的那么干净,但是所有的清洁方法对我都没有效果。这将实现指定的行为:
目录结构:
1 2 3 4 5 6 7 8 | | pkg |--| __init__.py | main.py | scripts |--| __init__.py | script1.py | script2.py | script3.py |
其中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | import importlib as _importlib import pkgutil as _pkgutil __all__ = [_mod[1].split(".")[-1] for _mod in filter(lambda _mod: _mod[1].count(".") == 1 and not _mod[2] and __name__ in _mod[1], [_mod for _mod in _pkgutil.walk_packages("." + __name__)])] __sub_mods__ = [".".join(_mod[1].split(".")[1:]) for _mod in filter(lambda _mod: _mod[1].count(".") > 1 and not _mod[2] and __name__ in _mod[1], [_mod for _mod in _pkgutil.walk_packages("." + __name__)])] from . import * for _module in __sub_mods__: _importlib.import_module("." + _module, package=__name__) |
虽然它很乱,但应该是便携式的。我已经为几个不同的包使用了这个代码。
我自己也厌倦了这个问题,所以我写了一个叫做automodinit的包来解决它。您可以从http://pypi.python.org/pypi/automodinit/获得它。用法如下:
1 2 3 4 5 6 | __all__ = ["I will get rewritten"] # Don't modify the line above, or this line! import automodinit automodinit.automodinit(__name__, __file__, globals()) del automodinit # Anything else you want can go after here, it won't get modified. |
就是这样!从现在起,导入模块会将
1 | for x in __all__: import x |
因此,
automodinit很高兴从zip文件中运行,因此是zip安全的。
我一直在玩弄乔·金顿的答案,并建立了一个使用
还要注意,ops问题只讨论从包中导入所有模块,此代码也递归地导入所有包。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | from pkgutil import walk_packages from os import path __all__ = [] __pkg_prefix ="%s." % __name__ __pkg_path = path.abspath(__path__[0]).rsplit("/", 1)[0] #parent directory for loader, modname, _ in walk_packages([__pkg_path]): if modname.startswith(__pkg_prefix): #load the module / package module = loader.find_module(modname).load_module(modname) modname = modname[len(__pkg_prefix):] #strip package prefix from name #append all toplevel modules and packages to __all__ if not"." in modname: __all__.append(modname) globals()[modname] = module #set everything else as an attribute of their parent package else: #get the toplevel package from globals() pkg_name, rest = modname.split(".", 1) pkg = globals()[pkg_name] #recursively get the modules parent package via getattr while"." in rest: subpkg, rest = rest.split(".", 1) pkg = getattr(pkg, subpkg) #set the module (or package) as an attribute of its parent package setattr(pkg, rest, module) |
作为未来的改进,我将尝试在包上使用
在python 3中,可以将以下代码放入
1 2 3 4 5 6 7 8 9 10 11 12 | import os import os.path as op __all__ = [ op.splitext(f)[0] # remove .py extension for f in os.listdir(BASE_DIR) # list contents of current dir if not f.startswith('_') and ((op.isfile(op.join(BASE_DIR, f)) and f.endswith('.py')) or (op.isdir(op.join(BASE_DIR, f)) and op.isfile(op.join(BASE_DIR, f, '__init__.py')))) ] from . import * # to make `scripts.script1` work after `import script` |
关于python导入的更多信息,我推荐david beazley在pycon 2015上的演讲:https://youtu.be/0oth1cxraq0
在python 3.3中,这对我很有用。注意,这只适用于与
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | from glob import iglob from os.path import basename, relpath, sep, splitext def import_submodules(__path__to_here): """Imports all submodules. Import this function in __init__.py and put this line to it: __all__ = import_submodules(__path__)""" result = [] for smfile in iglob(relpath(__path__to_here[0]) +"/*.py"): submodule = splitext(basename(smfile))[0] importstr =".".join(smfile.split(sep)[:-1]) if not submodule.startswith("_"): __import__(importstr +"." + submodule) result.append(submodule) return result |
我一直在编写一个小型的个人库,并添加新的模块,所以我编写了一个shell脚本来查找脚本并创建
我知道这可能不是你想要的答案,但它为我实现了它的目标,对其他人也可能有用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | #!/bin/bash echo 'Traversing folder hierarchy...' CWD=`pwd` for directory in `find pylux -type d -exec echo {} \;`; do cd $directory #echo Entering $directory echo -n""> __init__.py for subdirectory in `find . -type d -maxdepth 1 -mindepth 1`; do subdirectory=`echo $subdirectory | cut -b 3-` #echo -n ' ' ...$subdirectory #echo -e '\t->\t' import $subdirectory echo import $subdirectory >> __init__.py done for pyfile in *.py ; do if [ $pyfile = $(echo __init__.py) ]; then continue fi #echo -n ' ' ...$pyfile #echo -e '\t->\t' import `echo $pyfile | cut -d . -f 1` echo import `echo $pyfile | cut -d . -f 1` >> __init__.py done cd $CWD done for directory in `find pylux -type d -exec echo {} \;`; do echo $directory/__init__.py: cat $directory/__init__.py | awk '{ print"\t"$0 }' done |