包 __init__.py 导入所有子文件,但只从另一个脚本加载一个?
Package __init__.py import all subfiles, but only load one from another script?
我创建了一个文件结构如下的包:
- package
- __init__.py
- load.py
- train.py
- test.py
我的 __init__.py
文件只是这些文件的 classes 的导入:
from package.load import Load
from package.train import Train
from package.test import Test
大多数时候,我想加载全部三个,但有时我只想加载其中一个 class。例如,在一个临时脚本(包外)中,我希望只能像这样调用 Load class:
from package import Load
虽然上述所有方法都适用于此设计,但我有一个问题,当我像上面那样导入 Load
时,来自 train/test 的依赖项也会被加载。我如何设置 __init__.py
文件,以便我可以进行相同的 import
调用而无需从 train/test 加载依赖项?
补充说明:
我为什么这样做:我有一个问题,我希望一些人能够使用 Load
class,它只使用基础 python,但是 Train/Test 文件包含专门的依赖项,只有 Load class 的用户不想使用甚至安装这些依赖项。
这是一种非常接近您想要的方式。您可以在其中定义一个函数来显式导入任何所需的函数,而不是无条件地 import
ing 所有包的 classes 在您的 __init__.py
中(如果 [=39 则全部导入) =] 已指定)。
__init__.py
:
from pathlib import Path
import sys
print(f'In {Path(__file__).name}')
package_name = Path(__file__).parent.name
package_prefix = package_name + '.'
class_to_module_map = {'Load': 'load', 'Train': 'train', 'Test': 'test'}
def import_classes(*class_names):
namespace = sys._getframe(1).f_globals # Caller's globals.
if not class_names:
class_names = class_to_module_map.keys() # Import them all.
for class_name in class_names:
module = class_to_module_map[class_name]
temp = __import__(package_prefix+module, globals(), locals(), [class_name])
namespace[class_name] = getattr(temp, class_name) # Add to caller's namespace.
出于测试目的,这是我在 load.py
脚本中输入的内容:
(我还在其他两个模块中放了类似的东西,以验证它们是否得到 import
ed。)
load.py
:
from pathlib import Path
print(f'In {Path(__file__).name}')
class Load: pass
最后是一个仅用于 import
Load
class:
的示例
ad_hoc.py
:
from my_package import import_classes
#from my_package import Load
import_classes('Load')
test = Load()
print(test)
连同产生的输出:
In __init__.py
In load.py
<my_package.load.Load object at 0x001FE4A8>
在文件夹 oranges\
中,这是我们的 __init__.py
文件:
__all__ = []
from pathlib import Path
from importlib import import_module
from sys import modules
package = modules[__name__]
initfile = Path(__file__)
for entry in initfile.parent.iterdir():
is_file = entry.is_file()
is_pyfile = entry.name.endswith('.py')
is_not_initpy = (entry != initfile)
if is_file and is_pyfile and is_not_initpy:
module_name = entry.name.removesuffix('.py')
module_path = __name__ + '.' + module_name
module = import_module(module_path)
setattr(package, module_name, module)
__all__.append(module_name)
当我们执行 from oranges import *
时,oranges\__init__.py
中的代码循环遍历 oranges\
中的 *.py
个文件(__init__.py
除外),并且对于每个 .py
文件执行以下操作:
使用Python的importlib.import_module
将.py
文件作为模块导入变量module
将 module
设置为 __init__.py
文件中的变量(或者更准确地说,在 oranges 包中)使用Python的setattr
最后,将模块附加到 __all__
列表
我创建了一个文件结构如下的包:
- package
- __init__.py
- load.py
- train.py
- test.py
我的 __init__.py
文件只是这些文件的 classes 的导入:
from package.load import Load
from package.train import Train
from package.test import Test
大多数时候,我想加载全部三个,但有时我只想加载其中一个 class。例如,在一个临时脚本(包外)中,我希望只能像这样调用 Load class:
from package import Load
虽然上述所有方法都适用于此设计,但我有一个问题,当我像上面那样导入 Load
时,来自 train/test 的依赖项也会被加载。我如何设置 __init__.py
文件,以便我可以进行相同的 import
调用而无需从 train/test 加载依赖项?
补充说明:
我为什么这样做:我有一个问题,我希望一些人能够使用 Load
class,它只使用基础 python,但是 Train/Test 文件包含专门的依赖项,只有 Load class 的用户不想使用甚至安装这些依赖项。
这是一种非常接近您想要的方式。您可以在其中定义一个函数来显式导入任何所需的函数,而不是无条件地 import
ing 所有包的 classes 在您的 __init__.py
中(如果 [=39 则全部导入) =] 已指定)。
__init__.py
:
from pathlib import Path
import sys
print(f'In {Path(__file__).name}')
package_name = Path(__file__).parent.name
package_prefix = package_name + '.'
class_to_module_map = {'Load': 'load', 'Train': 'train', 'Test': 'test'}
def import_classes(*class_names):
namespace = sys._getframe(1).f_globals # Caller's globals.
if not class_names:
class_names = class_to_module_map.keys() # Import them all.
for class_name in class_names:
module = class_to_module_map[class_name]
temp = __import__(package_prefix+module, globals(), locals(), [class_name])
namespace[class_name] = getattr(temp, class_name) # Add to caller's namespace.
出于测试目的,这是我在 load.py
脚本中输入的内容:
(我还在其他两个模块中放了类似的东西,以验证它们是否得到 import
ed。)
load.py
:
from pathlib import Path
print(f'In {Path(__file__).name}')
class Load: pass
最后是一个仅用于 import
Load
class:
ad_hoc.py
:
from my_package import import_classes
#from my_package import Load
import_classes('Load')
test = Load()
print(test)
连同产生的输出:
In __init__.py
In load.py
<my_package.load.Load object at 0x001FE4A8>
在文件夹 oranges\
中,这是我们的 __init__.py
文件:
__all__ = []
from pathlib import Path
from importlib import import_module
from sys import modules
package = modules[__name__]
initfile = Path(__file__)
for entry in initfile.parent.iterdir():
is_file = entry.is_file()
is_pyfile = entry.name.endswith('.py')
is_not_initpy = (entry != initfile)
if is_file and is_pyfile and is_not_initpy:
module_name = entry.name.removesuffix('.py')
module_path = __name__ + '.' + module_name
module = import_module(module_path)
setattr(package, module_name, module)
__all__.append(module_name)
当我们执行 from oranges import *
时,oranges\__init__.py
中的代码循环遍历 oranges\
中的 *.py
个文件(__init__.py
除外),并且对于每个 .py
文件执行以下操作:
使用Python的
将importlib.import_module
.py
文件作为模块导入变量module
将
module
设置为__init__.py
文件中的变量(或者更准确地说,在 oranges 包中)使用Python的setattr
最后,将模块附加到
__all__
列表