有人可以为我提供导入整个模块目录的好方法吗?
我有这样的结构:
/Foo
bar.py
spam.py
eggs.py
我尝试通过添加__init__.py
和执行操作将其转换为程序包,from Foo import *
但它没有达到我希望的方式。
有人可以为我提供导入整个模块目录的好方法吗?
我有这样的结构:
/Foo
bar.py
spam.py
eggs.py
我尝试通过添加__init__.py
和执行操作将其转换为程序包,from Foo import *
但它没有达到我希望的方式。
Answers:
列出.py
当前文件夹中的所有python()文件,并将它们作为__all__
变量放入__init__.py
from os.path import dirname, basename, isfile, join
import glob
modules = glob.glob(join(dirname(__file__), "*.py"))
__all__ = [ basename(f)[:-3] for f in modules if isfile(f) and not f.endswith('__init__.py')]
if not os.path.basename(f).startswith('_')
至少if not f.endswith('__init__.py')
是列表理解的末尾
os.path.isfile(f)
为True
。这样可以过滤掉损坏的符号链接和目录,例如somedir.py/
(我承认,但仍然...)
from . import *
设置后__all__
,如果您希望子模块可使用.
(例如,如module.submodule1
,module.submodule2
等)。
将__all__
变量添加到__init__.py
包含:
__all__ = ["bar", "spam", "eggs"]
moduleName.varName
ref。stackoverflow.com/a/710603/248616
2017年更新:您可能想使用它importlib
。
通过添加Foo目录使Foo目录成为一个包__init__.py
。在其中__init__.py
添加:
import bar
import eggs
import spam
由于您希望它是动态的(这可能不是一个好主意),因此,请使用list dir列出所有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
等等from Foo import *
并不是一个好主意,原因有几个,其中包括名称冲突以及难以分析代码。
__import__
__all__
from . import *
__import__
不为一般用途,它使用的interpreter
,使用importlib.import_module()
来代替。
from . import eggs
等在__init__.py
之前的Python可以导入。尝试进入以上目录中的时,只有import eggs
我得到。ModuleNotFoundError: No module named 'eggs'
import Foo
main.py
扩展Mihail的答案,我相信这种非骇客的方式(例如,不直接处理文件路径)如下:
__init__.py
文件Foo/
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'>
RuntimeWarning
通过完全不使用full_package_name,也可以避免这些消息importer.find_module(package_name).load_module(package_name)
。
RuntimeWarning
还可以通过导入父(AKA目录名)来避免错误(在一个可以说是丑陋的方式)。一种方法是- if dirname not in sys.modules: pkgutil.find_loader(dirname).load_module(dirname)
。当然,只有dirname
在单组分相对路径下才有效。没有斜线。就个人而言,我更喜欢@Artfunkel的使用基本package_name的方法。
对于只是无法使用它的新手,他们需要手牵着手。
创建一个文件夹/ home / el / foo并main.py
在/ home / el / foo下创建一个文件将以下代码放在其中:
from hellokitty import *
spam.spamfunc()
ham.hamfunc()
建立目录 /home/el/foo/hellokitty
使文件__init__.py
下/home/el/foo/hellokitty
,并把这个代码有:
__all__ = ["spam", "ham"]
让两个Python文件:spam.py
和ham.py
下/home/el/foo/hellokitty
在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
import *
被认为是不好的Python编码实践。没有这个,您该怎么做?
我自己对这个问题感到厌倦,所以写了一个叫做automodinit的软件包来解决它。您可以从http://pypi.python.org/pypi/automodinit/获取。
用法是这样的:
automodinit
软件包包括在您的setup.py
依赖项中。__all__ = [“我将被重写”] #请勿修改上方的行或该行! 导入automodinit automodinit.automodinit(__ name__,__file__,globals()) 自动修改 #您想要的其他任何东西都可以在这里进行,它不会被修改。
而已!从现在开始,导入模块会将__all__设置为模块中.py [co]文件的列表,并且还将导入每个文件,就像您键入的一样:
for x in __all__: import x
因此,“从M import *”的效果与“ import M”完全匹配。
automodinit
很高兴从ZIP档案内部运行,因此是ZIP安全的。
尼尔
我知道我正在更新一个很旧的帖子,我尝试使用automodinit
,但是发现它的设置过程对于python3来说是坏的。因此,基于Luca的答案,我针对此问题提出了一个更简单的答案(可能不适用于.zip),因此我认为应该在此处共享它:
在以下__init__.py
模块中yourpackage
:
#!/usr/bin/env python
import os, pkgutil
__all__ = list(module for _, module, _ in pkgutil.iter_modules([os.path.dirname(__file__)]))
在下面的另一个包中yourpackage
:
from yourpackage import *
然后,将装入包中放置的所有模块,并且如果您编写一个新模块,则该模块也会自动导入。当然,小心翼翼地使用这种东西会带来巨大的责任。
我也遇到了这个问题,这是我的解决方案:
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()
此函数创建一个名为的文件(在提供的文件夹中)__init__.py
,该文件包含一个__all__
变量,用于保存文件夹中的每个模块。
例如,我有一个名为的文件夹Test
,其中包含:
Foo.py
Bar.py
因此,在脚本中,我希望将模块导入其中:
loadImports('Test/')
from Test import *
这将导入所有内容,Test
并且其中的__init__.py
文件Test
现在将包含:
__all__ = ['Foo','Bar']
Anurag Uniyal的答案有建议的改进!
#!/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
看到您的__init__.py
定义__all__
。该模块-包医生说
这些
__init__.py
文件是使Python将目录视为包含包所必需的;这样做是为了防止具有通用名称的目录(例如字符串)无意间隐藏了稍后在模块搜索路径中出现的有效模块。在最简单的情况下,__init__.py
可以只是一个空文件,但也可以执行该程序包的初始化代码或设置__all__
变量,如下所述。...
唯一的解决方案是让程序包作者提供程序包的显式索引。import语句使用以下约定:如果程序包的
__init__.py
代码定义了一个名为的列表__all__
,则将其视为遇到从包import *时应导入的模块名称的列表。发行新版本的软件包时,软件包作者有责任使此列表保持最新。如果软件包作者没有看到从软件包中导入*的用途,他们可能还会决定不支持它。例如,该文件sounds/effects/__init__.py
可能包含以下代码:
__all__ = ["echo", "surround", "reverse"]
这意味着
from sound.effects import *
将导入声音包的三个命名子模块。
使用importlib
你要添加的唯一事情是
from importlib import import_module
from pathlib import Path
__all__ = [
import_module(f".{f.stem}", __package__)
for f in Path(__file__).parent.glob("*.py")
if "__" not in f.stem
]
del import_module, Path
error: Type of __all__ must be "Sequence[str]", not "List[Module]"
。__all__
如果使用这种import_module
基于方法,则不需要定义。
查看标准库中的pkgutil模块。只要__init__.py
目录中有文件,它就可以让您执行所需的操作。该__init__.py
文件可以为空。
我为此创建了一个模块,该模块不依赖__init__.py
(或任何其他辅助文件),仅键入以下两行:
import importdir
importdir.do("Foo", globals())
随时重用或贡献:http : //gitlab.com/aurelien-lourot/importdir
只需通过importlib导入它们,然后将它们递归添加到软件包中__all__
(add
操作是可选的)__init__.py
。
/Foo
bar.py
spam.py
eggs.py
__init__.py
# __init__.py
import os
import importlib
pyfile_extes = ['py', ]
__all__ = [importlib.import_module('.%s' % filename, __package__) for filename in [os.path.splitext(i)[0] for i in os.listdir(os.path.dirname(__file__)) if os.path.splitext(i)[1] in pyfile_extes] if not filename.startswith('__')]
del os, importlib, pyfile_extes
py
当from . import *
不够好时,这是对ted答案的改进。具体而言,在__all__
此方法中无需使用。
"""Import all modules that exist in the current directory."""
# Ref https://stackoverflow.com/a/60861023/
from importlib import import_module
from pathlib import Path
for f in Path(__file__).parent.glob("*.py"):
module_name = f.stem
if (not module_name.startswith("_")) and (module_name not in globals()):
import_module(f".{module_name}", __package__)
del f, module_name
del import_module, Path
请注意,这module_name not in globals()
是为了避免重新导入模块(如果已导入),因为这可能会导致循环导入。