使用Python将所有模块加载到文件夹中
有人能提供一个导入整个模块目录的好方法吗?
我有这样的结构:
/Foo bar.py spam.py eggs.py
我试着把它转换成一个包,通过添加__init__.py
并from Foo import *
但它没有按照我所希望的方式工作。
将__all__
variables添加到__init__.py
其中包含:
__all__ = ["bar", "spam", "eggs"]
列出当前文件夹中的所有python( .py
)文件,并将它们作为__all__
variables放在__init__.py
from os.path import dirname, basename, isfile import glob modules = glob.glob(dirname(__file__)+"/*.py") __all__ = [ basename(f)[:-3] for f in modules if isfile(f) and not f.endswith('__init__.py')]
更新:今天你可能想用importlib
来代替。
通过添加一个__init__.py
使Foo目录成为一个包。 在这__init__.py
添加:
import bar import eggs import spam
既然你想dynamic的(这可能也可能不是一个好主意),列出所有的py文件列表目录和导入他们这样的东西:
import os for module in os.listdir(os.path.dirname(__file__)): if module == '__init__.py' or module[-3:] != '.py': continue __import__(module[:-3], locals(), globals()) del module
然后,从你的代码做到这一点:
import Foo
您现在可以通过访问模块
Foo.bar Foo.eggs Foo.spam
从Foo导入*等不是一个好主意,有几个原因,包括名称冲突,并使其难以分析代码。
扩展Mihail的答案,我相信这个非hackish的方式(如,不直接处理文件path)如下:
- 在
Foo/
下创build一个空的__init__.py
文件, - 执行
import pkgutil import sys def load_all_modules_from_dir(dirname): for importer, package_name, _ in pkgutil.iter_modules([dirname]): full_package_name = '%s.%s' % (dirname, package_name) if full_package_name not in sys.modules: module = importer.find_module(package_name ).load_module(full_package_name) print module load_all_modules_from_dir('Foo')
你会得到:
<module 'Foo.bar' from '/home/.../Foo/bar.pyc'> <module 'Foo.spam' from '/home/.../Foo/spam.pyc'>
Python,包括一个目录下的所有文件:
对于那些不能上class的新手而言,
-
创build一个文件夹/ home / el / foo并在/ home / el / foo下创build一个文件
main.py
把这个代码放在那里:from hellokitty import * spam.spamfunc() ham.hamfunc()
-
build立一个目录
/home/el/foo/hellokitty
-
在
/home/el/foo/hellokitty
下创build一个文件__init__.py
,并把这个代码放在那里:__all__ = ["spam", "ham"]
-
在
/home/el/foo/hellokitty
下创build两个python文件:spam.py
和ham.py
-
在spam.py中定义一个函数:
def spamfunc(): print "Spammity spam"
-
在ham.py中定义一个函数:
def hamfunc(): print "Upgrade from baloney"
-
运行:
el@apollo:/home/el/foo$ python main.py spammity spam Upgrade from baloney
我自己已经厌倦了这个问题,所以我写了一个名为automodinit的包来修复它。 你可以从http://pypi.python.org/pypi/automodinit/得到它。;
用法如下所示:
- 将
automodinit
包纳入setup.py
依赖关系。 - 把所有的__init__.py文件replace成这样:
__all__ = [“我将被重写”] #不要修改上面的行或这一行! 导入automodinit automodinit.automodinit(__ name__,__file__,globals()) del automodinit #任何你想要的东西都可以在这里之后去,它不会被修改。
而已! 从现在开始,导入模块会将__all__设置为模块中的.py [co]文件列表,并且还将导入每个文件,就好像您input了:
for x in __all__: import x
因此,“从M导入*”的效果恰好与“导入M”匹配。
automodinit
很高兴从ZIP档案里面运行,因此ZIP是安全的。
尼尔
我也遇到了这个问题,这是我的解决scheme:
import os def loadImports(path): files = os.listdir(path) imps = [] for i in range(len(files)): name = files[i].split('.') if len(name) > 1: if name[1] == 'py' and name[0] != '__init__': name = name[0] imps.append(name) file = open(path+'__init__.py','w') toWrite = '__all__ = '+str(imps) file.write(toWrite) file.close()
该函数创build一个名为__init__.py
的文件(在提供的文件夹中),其中包含一个__all__
variables,用于保存文件夹中的每个模块。
例如,我有一个名为Test
的文件夹,其中包含:
Foo.py Bar.py
所以在脚本中,我想要将模块导入到我将写入:
loadImports('Test/') from Test import *
这将导入Test
所有内容, Test
的__init__.py
文件现在包含:
__all__ = ['Foo','Bar']
Anurag Uniyal回答build议的改进!
#!/usr/bin/python # -*- encoding: utf-8 -*- import os import glob all_list = list() for f in glob.glob(os.path.dirname(__file__)+"/*.py"): if os.path.isfile(f) and not os.path.basename(f).startswith('_'): all_list.append(os.path.basename(f)[:-3]) __all__ = all_list
Anurag的例子有几个更正:
import os, glob modules = glob.glob(os.path.join(os.path.dirname(__file__), "*.py")) __all__ = [os.path.basename(f)[:-3] for f in modules if not f.endswith("__init__.py")]
看到你的__init__.py
定义了__all__
。 模块 – 包 doc说
需要使用
__init__.py
文件来使Python将目录视为包含包; 这是为了防止具有通用名称的目录(如string)无意中隐藏稍后在模块searchpath中发生的有效模块。 在最简单的情况下,__init__.py
可以只是一个空文件,但它也可以执行包的初始化代码或设置__all__
variables,稍后介绍。…
唯一的解决scheme是软件包作者提供一个明确的软件包索引。 import语句使用以下约定:如果某个包的
__init__.py
代码定义了一个名为__all__
的列表,则将其视为遇到包import *时应导入的模块名列表。 当软件包的新版本发布时,软件包作者应该保持这个列表是最新的。 软件包作者也可能决定不支持它,如果他们没有看到从包中导入*的用法。 例如,文件sounds/effects/__init__.py
可能包含以下代码:
__all__ = ["echo", "surround", "reverse"]
这意味着
from sound.effects import *
会导入声音包的三个命名的子模块。
这是迄今为止我发现的最好的方法:
from os.path import dirname, join, isdir, abspath, basename from glob import glob pwd = dirname(__file__) for x in glob(join(pwd, '*.py')): if not x.startswith('__'): __import__(basename(x)[:-3], globals(), locals())
我知道我正在更新一个相当古老的post,我尝试使用automodinit
,但发现它的设置过程是打破了python3。 所以,基于卢卡的回答,我想出了一个更简单的答案 – 这可能不适用于.zip – 这个问题,所以我想我应该在这里分享:
在你的yourpackage
的__init__.py
模块中:
#!/usr/bin/env python import os, pkgutil __all__ = list(module for _, module, _ in pkgutil.iter_modules([os.path.split(__file__)[0])
并在您的包装下的另一个包装内:
from yourpackage import *
然后你将所有放在包中的模块加载,如果你写了一个新的模块,它也会被自动导入。 当然,谨慎使用这种事情,大国有很大的责任。
import pkgutil __path__ = pkgutil.extend_path(__path__, __name__) for imp, module, ispackage in pkgutil.walk_packages(path=__path__, prefix=__name__+'.'): __import__(module)
查看标准库中的pkgutil模块。 只要你在目录中有一个__init__.py
文件,它就可以让你做你想要的东西。 __init__.py
文件可以是空的。
我创build了一个模块,它不依赖于__init__.py
. __init__.py
(或任何其他辅助文件),并使我只键入以下两行:
import importdir importdir.do("Foo", globals())
随意重新使用或贡献: http : //gitlab.com/aurelien-lourot/importdir