如何加载文件夹中的所有模块?

2024-12-17 08:30:00
admin
原创
129
摘要:问题描述:有人能给我提供一个导入整个模块目录的好方法吗? 我有一个这样的结构:/Foo bar.py spam.py eggs.py __init__.py我尝试通过添加和执行将其转换为包from Foo import *,但它并没有像我希望的那样工作。解决方案 1:列出.py当前文...

问题描述:

有人能给我提供一个导入整个模块目录的好方法吗?

我有一个这样的结构:

/Foo
    bar.py
    spam.py
    eggs.py

__init__.py我尝试通过添加和执行将其转换为包from Foo import *,但它并没有像我希望的那样工作。


解决方案 1:

列出.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')]

解决方案 2:

添加__all__变量以__init__.py包含:

__all__ = ["bar", "spam", "eggs"]

另请参阅http://docs.python.org/tutorial/modules.html

解决方案 3:

2017 年更新:您可能想使用importlib

通过添加 . 将 Foo 目录变成一个包,__init__.py在其中__init__.py添加:

import bar
import eggs
import spam

因为你想要动态的(这可能是也可能不是一个好主意),用列表目录列出所有的 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 *并不是一个好主意,原因有几个,包括名称冲突和难以分析代码。

解决方案 4:

Python,包含某个目录下的所有文件:

对于那些无法操作且需要有人指导的新手来说。

  1. 创建一个文件夹 /home/el/foo,并main.py在 /home/el/foo 下创建一个文件,将以下代码放入其中:

from hellokitty import *
spam.spamfunc()
ham.hamfunc()
  1. 创建目录/home/el/foo/hellokitty

  2. __init__.py在下面创建一个文件/home/el/foo/hellokitty并将以下代码放入其中:

__all__ = ["spam", "ham"]
  1. 创建两个python文件:spam.pyham.py`/home/el/foo/hellokitty`

  2. 在 spam.py 中定义一个函数:

def spamfunc():
  print("Spammity spam")
  1. 在ham.py里面定义一个函数:

def hamfunc():
  print("Upgrade from baloney")
  1. 运行它:

el@apollo:/home/el/foo$ python main.py 
spammity spam
Upgrade from baloney

解决方案 5:

扩展 Mihail 的回答,我相信非黑客的方式(例如,不直接处理文件路径)如下:

  1. 在下面创建一个空__init__.py文件Foo/

  2. 执行

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'>

解决方案 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 *

然后,您将加载包内的所有模块,如果您编写了新模块,它也将自动导入。当然,使用这类东西时要小心,能力越大,责任越大。

解决方案 7:

我自己也厌倦了这个问题,所以我写了一个名为 automodinit 的包来修复它。你可以从http://pypi.python.org/pypi/automodinit/获取它。

使用方式如下:

  1. 将该automodinit包包含到您的setup.py依赖项中。

  2. 将所有 __init__.py 文件替换为:

__all__ = [“我将得到重写”]
# 不要修改上面这一行,或者这一行!
导入自动模式
automodinit.automodinit(__name__, __file__,globals())
德尔奥托莫迪尼特
# 您想要的任何其他内容都可以放在这里,不会被修改。

就是这样!从现在开始,导入模块将把 all 设置为模块中的 .py[co] 文件列表,并且还将导入每个文件,就像您输入以下内容一样:

for x in __all__: import x

因此“from M import *”的效果与“import M”完全匹配。

automodinit很高兴能从 ZIP 档案中运行,因此 ZIP 是安全的。

尼尔

解决方案 8:

import pkgutil
__path__ = pkgutil.extend_path(__path__, __name__)
for imp, module, ispackage in pkgutil.walk_packages(path=__path__, prefix=__name__+'.'):
  __import__(module)

解决方案 9:

我也遇到了这个问题,这是我的解决方案:

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']

解决方案 10:

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()是为了避免在模块已经导入的情况下重新导入,因为这可能会带来循环导入的风险。

解决方案 11:

这是迄今为止我发现的最好的方法:

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())

解决方案 12:

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  

解决方案 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

解决方案 14:

我想补充一下Anurag Uniyal的回答。您可以让它更简单,并摆脱许多导入。__init__.py 文件的内容:

from os import listdir
from os.path import dirname
__all__ = [i[:-3] for i in listdir(dirname(__file__)) if not i.startswith('__') and i.endswith('.py')]

解决方案 15:

我为此创建了一个模块,它不依赖于__init__.py(或任何其他辅助文件)并且只需要输入以下两行:

import importdir
importdir.do("Foo", globals())

欢迎随意重复使用或贡献:http ://gitlab.com/aurelien-lourot/importdir

解决方案 16:

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")]

解决方案 17:

看看你的__init__.py定义__all__。模块-包文档说

这些__init__.py文件是使 Python 将目录视为包含包所必需的;这样做是为了防止具有通用名称(例如字符串)的目录无意中隐藏稍后在模块搜索路径中出现的有效模块。在最简单的情况下,__init__.py可以只是一个空文件,但它也可以执行包的初始化代码或设置__all__变量,稍后会介绍。

...

唯一的解决方案是让包作者提供包的明确索引。 import 语句使用以下约定:如果包的__init__.py代码定义了一个名为 的列表__all__,则当遇到 from package import 时,它将被视为应导入的模块名称列表。当发布新版本的包时,包作者有责任保持此列表为最新。如果包作者认为从他们的包中导入 没有用,他们也可能决定不支持它。例如,该文件sounds/effects/__init__.py可能包含以下代码:

__all__ = ["echo", "surround", "reverse"]

这意味着from sound.effects import *将导入声音包的三个命名子模块。

解决方案 18:

在 Python 3.9.5、Flask 2.2.2 中,所有解决方案都对我不起作用,模块是 cwd 下 2 级目录。这是我的解决方案:

import importlib
import pathlib
import re

path = pathlib.Path(__file__).parent.absolute()
names = [x.name[:-3] for x in path.iterdir() if x.is_file() and re.search("^[a-z]*.py$", x.name)]
for name in names:
    importlib.import_module(f".{name}", __name__)

解决方案 19:

查看标准库中的 pkgutil 模块。只要__init__.py目录中有一个文件,它就能让你做你想做的事。该__init__.py文件可以是空的。

解决方案 20:

只需通过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

解决方案 21:

这是一个解决方案,您不必写文件名。只需将此代码片段添加到您的__init__.py

from inspect import isclass
from pkgutil import iter_modules
from pathlib import Path
from importlib import import_module

# iterate through the modules in the current package
package_dir = Path(__file__).resolve().parent
for (_, module_name, _) in iter_modules([package_dir]):

    # import the module and iterate through its attributes
    module = import_module(f"{__name__}.{module_name}")
    for attribute_name in dir(module):
        attribute = getattr(module, attribute_name)

        if isclass(attribute):            
            # Add the class to this package's variables
            globals()[attribute_name] = attribute

来源

解决方案 22:

我有一个嵌套的目录结构,即在主目录内有多个包含 python 模块的目录。

我将以下脚本添加到我的__init__.py文件中以导入所有模块

import glob, re, os 

module_parent_directory = "path/to/the/directory/containing/__init__.py/file"

owd = os.getcwd()
if not owd.endswith(module_parent_directory): os.chdir(module_parent_directory)

module_paths = glob.glob("**/*.py", recursive = True)

for module_path in module_paths:
    if not re.match( ".*__init__.py$", module_path):
        import_path = module_path[:-3]
        import_path = import_path.replace("/", ".")
        exec(f"from .{import_path} import *")

os.chdir(owd)

这可能不是实现这一目标的最佳方法,但我无法让其他任何方法为我工作。

相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   1565  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1354  
  信创国产芯片作为信息技术创新的核心领域,对于推动国家自主可控生态建设具有至关重要的意义。在全球科技竞争日益激烈的背景下,实现信息技术的自主可控,摆脱对国外技术的依赖,已成为保障国家信息安全和产业可持续发展的关键。国产芯片作为信创产业的基石,其发展水平直接影响着整个信创生态的构建与完善。通过不断提升国产芯片的技术实力、产...
国产信创系统   21  
  信创生态建设旨在实现信息技术领域的自主创新和安全可控,涵盖了从硬件到软件的全产业链。随着数字化转型的加速,信创生态建设的重要性日益凸显,它不仅关乎国家的信息安全,更是推动产业升级和经济高质量发展的关键力量。然而,在推进信创生态建设的过程中,面临着诸多复杂且严峻的挑战,需要深入剖析并寻找切实可行的解决方案。技术创新难题技...
信创操作系统   27  
  信创产业作为国家信息技术创新发展的重要领域,对于保障国家信息安全、推动产业升级具有关键意义。而国产芯片作为信创产业的核心基石,其研发进展备受关注。在信创国产芯片的研发征程中,面临着诸多复杂且艰巨的难点,这些难点犹如一道道关卡,阻碍着国产芯片的快速发展。然而,科研人员和相关企业并未退缩,积极探索并提出了一系列切实可行的解...
国产化替代产品目录   28  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用