python - "from src import *" 动态导入包或子包中的所有函数
问题描述
目标:
我希望能够通过“直接调用”动态导入子包中的所有函数
用法:
我的项目:
project/
|-- main.py
|-- src/
|---- __init__.py
|---- foo.py
|---- bar.py
foo.py
只有一个功能:
def foo_funct():
print("foo")
bar.py
只有一个功能:
def bar_funct():
print("bar")
最后main.py
:
from src import *
(...)
foo_funct()
bar_funct()
(...)
注释:
如果我
__init__.py
是这样的import os __all__ = [i.replace(".py", "") for i in os.listdir(os.getcwd()+"/src/") if "__" not in i]
我可以打电话
foo.foo_funct()
orbar.bar_funct()
但不能foo_funct()
orbar_funct()
如果我
__init__.py
是这样的:from src.foo import * from src.bar import *
我可以打电话
foo_funct()
,或者bar_funct()
但对于每个新的子包,我都必须修改我的__init__.py
假设这
from src import *
不是最pythonic的方法,并假设由于可能的命名冲突而直接调用可能非常危险,例如a.tree_funct()
andb.tree_funct()
,有什么方法可以达到我的目标吗?
解决方案
就个人而言,我更喜欢保持明确,只是将作为包 API 一部分的名称显式导入__init__
。您的项目不会变化得如此之快,以至于将所有内容动态导入到项目中将__init__.py
节省时间。
但如果你想这样做,那么你有几个选择。如果您需要支持 3.7 之前的 Python 版本,则可以通过查看globals()
字典来更新包命名空间。列出所有文件并使用(或者如果您需要支持 2.7 之前的 Python 版本).py
导入它们:importlib.import_module()
__import__()
__all__ = []
def _load_all_submodules():
from pathlib import Path
from importlib import import_module
g = globals()
package_path = Path(__file__).resolve().parent
for pyfile in package_path.glob('*.py'):
module_name = pyfile.stem
if module_name == '__init__':
continue
module = import_module(f'.{module_name}', __package__)
names = getattr(
module, '__all__',
(n for n in dir(module) if n[:1] != '_'))
for name in names:
g[name] = getattr(module, name)
__all__.append(name)
_load_all_submodules()
del _load_all_submodules
以上保持命名空间干净;函数运行后,_load_all_submodules()
它会从包中删除。它使用__file__
全局来确定当前路径并.py
从那里找到任何同级文件。
如果只需要支持 Python 3.7 及以上版本,则可以定义模块级__getattr__()
和__dir__()
函数来实现动态查找。
在你的包文件中使用这些钩子__init__.py
可能看起来像:
def _find_submodules():
from pathlib import Path
from importlib import import_module
package_path = Path(__file__).resolve().parent
return tuple(p.stem for p in package_path.glob('*.py') if p.stem != '__init__')
__submodules__ = _find_submodules()
del _find_submodules
def __dir__():
from importlib import import_module
names = []
for module_name in __submodules__:
module = import_module(f'.{module_name}', __package__)
try:
names += module.__all__
except AttributeError:
names += (n for n in dir(module) if n[:1] != '_')
return sorted(names)
__all__ = __dir__()
def __getattr__(name):
from importlib import import_module
for module_name in __submodules__:
module = import_module(f'.{module_name}', __package__)
try:
# cache the attribute so future imports don't call __getattr__ again
obj = getattr(module, name)
globals()[name] = obj
return obj
except AttributeError:
pass
raise AttributeError(name)
推荐阅读
- javascript - 屏幕右边缘的Material-ui AppBar和Tab
- javascript - 如何在有行限制的 10 个字符后添加换行符
- javascript - 有没有办法在 React 中滚动到 div 或容器的底部而不将整个页面滚动到底部?
- java - 检查数组在函数中不起作用。(爪哇)
- javascript - React Native Drawer Navigation 总是自动关闭
- firebase - 删除 SwiftUI 后 Firebase Firestore 不更新 UI
- database - 如果名称在 Laravel 中重复,如何添加数量?
- c++ - DLL 函数参数类型不完整导致结果不正确
- node.js - Kubernetes 多容器通信
- android - 如何在android中将顶部手柄添加到底部?