问题:如何将所有模块加载到文件夹中?
有人可以为我提供导入整个模块目录的好方法吗?
我有这样的结构:
/Foo
bar.py
spam.py
eggs.py
我尝试通过添加__init__.py
和执行操作将其转换为程序包,from Foo import *
但它没有达到我希望的方式。
Could someone provide me with a good way of importing a whole directory of modules?
I have a structure like this:
/Foo
bar.py
spam.py
eggs.py
I tried just converting it to a package by adding __init__.py
and doing from Foo import *
but it didn’t work the way I had hoped.
回答 0
列出.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')]
List all python (.py
) files in the current folder and put them as __all__
variable in __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')]
回答 1
回答 2
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 *
并不是一个好主意,原因有几个,其中包括名称冲突以及难以分析代码。
Update in 2017: you probably want to use importlib
instead.
Make the Foo directory a package by adding an __init__.py
. In that __init__.py
add:
import bar
import eggs
import spam
Since you want it dynamic (which may or may not be a good idea), list all py-files with list dir and import them with something like this:
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
Then, from your code do this:
import Foo
You can now access the modules with
Foo.bar
Foo.eggs
Foo.spam
etc. from Foo import *
is not a good idea for several reasons, including name clashes and making it hard to analyze the code.
回答 3
扩展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'>
Expanding on Mihail’s answer, I believe the non-hackish way (as in, not handling the file paths directly) is the following:
- create an empty
__init__.py
file under Foo/
- Execute
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')
You’ll get:
<module 'Foo.bar' from '/home/.../Foo/bar.pyc'>
<module 'Foo.spam' from '/home/.../Foo/spam.pyc'>
回答 4
Python,将所有文件包含在目录下:
对于只是无法使用它的新手,他们需要手牵着手。
创建一个文件夹/ 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
Python, include all files under a directory:
For newbies who just can’t get it to work who need their hands held.
Make a folder /home/el/foo and make a file main.py
under /home/el/foo Put this code in there:
from hellokitty import *
spam.spamfunc()
ham.hamfunc()
Make a directory /home/el/foo/hellokitty
Make a file __init__.py
under /home/el/foo/hellokitty
and put this code in there:
__all__ = ["spam", "ham"]
Make two python files: spam.py
and ham.py
under /home/el/foo/hellokitty
Define a function inside spam.py:
def spamfunc():
print("Spammity spam")
Define a function inside ham.py:
def hamfunc():
print("Upgrade from baloney")
Run it:
el@apollo:/home/el/foo$ python main.py
spammity spam
Upgrade from baloney
回答 5
我自己对这个问题感到厌倦,所以写了一个叫做automodinit的软件包来解决它。您可以从http://pypi.python.org/pypi/automodinit/获取。
用法是这样的:
- 将
automodinit
软件包包括在您的setup.py
依赖项中。
- 像这样替换所有__init__.py文件:
__all__ = [“我将被重写”]
#请勿修改上方的行或该行!
导入automodinit
automodinit.automodinit(__ name__,__file__,globals())
自动修改
#您想要的其他任何东西都可以在这里进行,它不会被修改。
而已!从现在开始,导入模块会将__all__设置为模块中.py [co]文件的列表,并且还将导入每个文件,就像您键入的一样:
for x in __all__: import x
因此,“从M import *”的效果与“ import M”完全匹配。
automodinit
很高兴从ZIP档案内部运行,因此是ZIP安全的。
尼尔
I got tired of this problem myself, so I wrote a package called automodinit to fix it. You can get it from http://pypi.python.org/pypi/automodinit/.
Usage is like this:
- Include the
automodinit
package into your setup.py
dependencies.
- Replace all __init__.py files like this:
__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.
That’s it! From now on importing a module will set __all__ to
a list of .py[co] files in the module and will also import each
of those files as though you had typed:
for x in __all__: import x
Therefore the effect of “from M import *” matches exactly “import M”.
automodinit
is happy running from inside ZIP archives and is therefore ZIP safe.
Niall
回答 6
我知道我正在更新一个很旧的帖子,我尝试使用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 *
然后,将装入包中放置的所有模块,并且如果您编写一个新模块,则该模块也会自动导入。当然,小心翼翼地使用这种东西会带来巨大的责任。
I know I’m updating a quite old post, and I tried using automodinit
, but found out it’s setup process is broken for python3. So, based on Luca’s answer, I came up with a simpler answer – which might not work with .zip – to this issue, so I figured I should share it here:
within the __init__.py
module from yourpackage
:
#!/usr/bin/env python
import os, pkgutil
__all__ = list(module for _, module, _ in pkgutil.iter_modules([os.path.dirname(__file__)]))
and within another package below yourpackage
:
from yourpackage import *
Then you’ll have all the modules that are placed within the package loaded, and if you write a new module, it’ll be automagically imported as well. Of course, use that kind of things with care, with great powers comes great responsibilities.
回答 7
import pkgutil
__path__ = pkgutil.extend_path(__path__, __name__)
for imp, module, ispackage in pkgutil.walk_packages(path=__path__, prefix=__name__+'.'):
__import__(module)
import pkgutil
__path__ = pkgutil.extend_path(__path__, __name__)
for imp, module, ispackage in pkgutil.walk_packages(path=__path__, prefix=__name__+'.'):
__import__(module)
回答 8
我也遇到了这个问题,这是我的解决方案:
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']
I have also encountered this problem and this was my solution:
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()
This function creates a file (in the provided folder) named __init__.py
, which contains an __all__
variable that holds every module in the folder.
For example, I have a folder named Test
which contains:
Foo.py
Bar.py
So in the script I want the modules to be imported into I will write:
loadImports('Test/')
from Test import *
This will import everything from Test
and the __init__.py
file in Test
will now contain:
__all__ = ['Foo','Bar']
回答 9
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")]
Anurag’s example with a couple of corrections:
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")]
回答 10
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
Anurag Uniyal answer with suggested improvements!
#!/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
回答 11
看到您的__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 *
将导入声音包的三个命名子模块。
See that your __init__.py
defines __all__
. The modules – packages doc says
The __init__.py
files are required to make Python treat the directories as containing packages; this is done to prevent directories with a common name, such as string, from unintentionally hiding valid modules that occur later on the module search path. In the simplest case, __init__.py
can just be an empty file, but it can also execute initialization code for the package or set the __all__
variable, described later.
…
The only solution is for the package author to provide an explicit index of the package. The import statement uses the following convention: if a package’s __init__.py
code defines a list named __all__
, it is taken to be the list of module names that should be imported when from package import * is encountered. It is up to the package author to keep this list up-to-date when a new version of the package is released. Package authors may also decide not to support it, if they don’t see a use for importing * from their package. For example, the file sounds/effects/__init__.py
could contain the following code:
__all__ = ["echo", "surround", "reverse"]
This would mean that from sound.effects import *
would import the three named submodules of the sound package.
回答 12
这是到目前为止我发现的最好方法:
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())
This is the best way i’ve found so far:
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())
回答 13
使用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
Using importlib
the only thing you’ve got to add is
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
回答 14
查看标准库中的pkgutil模块。只要__init__.py
目录中有文件,它就可以让您执行所需的操作。该__init__.py
文件可以为空。
Look at the pkgutil module from the standard library. It will let you do exactly what you want as long as you have an __init__.py
file in the directory. The __init__.py
file can be empty.
回答 15
I’ve created a module for that, which doesn’t rely on __init__.py
(or any other auxiliary file) and makes me type only the following two lines:
import importdir
importdir.do("Foo", globals())
Feel free to re-use or contribute: http://gitlab.com/aurelien-lourot/importdir
回答 16
只需通过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
Just import them by importlib and add them to __all__
(add
action is optional) in recurse in the __init__.py
of package.
/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
回答 17
当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()
是为了避免重新导入模块(如果已导入),因为这可能会导致循环导入。
When from . import *
isn’t good enough, this is an improvement over the answer by ted. Specifically, the use of __all__
is not necessary with this approach.
"""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
Note that module_name not in globals()
is intended to avoid reimporting the module if it’s already imported, as this can risk cyclic imports.