可以,但不建议这么做。
考虑以下目录结构:
├── test_module
│ ├── ClassA.py
│ ├── ClassB.py
│ └── __init__.py
我们希望以编程方式将
ClassA.ClassA
和
ClassB.ClassB
导入到
__init__.py
中。
假设这是
ClassA.py
的内容:
class ClassA:
pass
ClassB.py
与之前的 class
名称不同,其他完全相同。
现在,假设我们想要在 __init__.py
中以非递归方式遍历根目录(尽管没有目录,但并不影响),并从所有模块中导入所有 classes
。
__init__.py
:
最初的回答:
import os
from importlib import import_module
my_location = os.path.dirname(__file__)
module_list = [file
for file in os.listdir(my_location)
if os.path.splitext(file)[1] == '.py'
and file != '__init__.py']
modules = [import_module(f'.{os.path.splitext(module)[0]}', __name__)
for module in module_list]
运行
import test_module
后,
ClassA.py
和
ClassB.py
中的
classes
将作为
test_module.ClassA.ClassA
和
test_module.ClassB.ClassB
导入到工作空间中。
举个例子:
>>> import test_module
>>> test_module.ClassA.ClassA()
<test_module.ClassA.ClassA object at 0x7f1e66181fd0>
为了完整性,如果您希望此脚本模仿
from X import Y
的行为:
globals().update({name: getattr(module, name)
for module in modules
for name in module.__dict__
if not name.startswith('_')})
导入:
>>> import test_module
>>> test_module.ClassA()
<test_module.ClassA.ClassA object at 0x7fb8edb9dfd0>
这将使得这些名称可以作为
test_module.ClassA
等访问(因为您是从
test_module
导入的,我们添加了一个额外的间接层)。在
test_module
的范围内,它们可以直接作为未限定名称访问。
我们可以添加其他功能,比如检查每个模块的
__all__
属性并执行子目录的递归遍历等,但这已经超出了这个问题的范围。我必须强调的是,在我看来,最好的做法是重构您的代码,以便首先不需要这样做,而不是添加与Python内部交互的功能,这似乎并不是必要的。
ClassName.py
文件中是一个不好的想法。如果你决定采用每个文件只有一个类的结构,请至少将其命名为classname.py
而不是ClassName.py
。将类和模块命名为相同的名称会导致奇怪的依赖于导入顺序的问题,有时你会得到类,有时你会得到模块。 - user2357112from com.mycompany.Foo import Foo
的调用。也许是类名的完全限定名,包括它的包名,让我免于麻烦。我确实认为我在其他包中经常遇到这种模式,但是再次强调,也许没有以这种方式导入。所以我并不是说你错了。我只是在多年的Python编程中没有遇到过这个问题。 - CryptoFoolfrom X import Y
中,X 不是总是一个包名而 Y 则总是一个符号名吗?我想不出这两者会有任何歧义的情况。 - CryptoFoolfrom com.mycompany.Foo import Foo
是足够安全的,但是看一下问题中的代码如何在__init__.py
中执行from .ClassA import ClassA
。这样做的整个目的是使from package import ClassA
导入类,但是根据导入顺序,它可能会导入类或模块。 - user2357112