【发布时间】:2017-03-19 18:55:18
【问题描述】:
我有一个基类和几个从它继承的子类。我正在尝试动态检测哪些子类动态地从基类继承。我目前是通过动态导入基类__init__()中的所有子类,然后使用__subclasses__()方法来实现的。
我的文件结构如下:
proj/
|-- __init__.py
|-- base.py
`-- sub
|-- __init__.py
|-- sub1.py
|-- sub2.py
`-- sub3.py
base.py:
import importlib
class Base(object):
def __init__(self):
importlib.import_module('sub.sub1')
importlib.import_module('sub.sub2')
importlib.import_module('sub.sub3')
@classmethod
def inheritors(cls):
print(cls.__subclasses__())
b = Base()
b.inheritors()
sub1.py:
import sys
import os
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from base import Base
class Sub1(Base):
pass
sub2.py:
import sys
import os
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from base import Base
class Sub2(Base):
pass
最后是 sub3.py:
import sys
import os
class Sub3(object):
pass
您会注意到sub.sub1.Sub1 和sub.sub2.Sub2 都继承自base.Base,而sub.sub3.Sub3 没有。
当我打开 IPython3 并运行 import base 时,我得到以下输出:
In [1]: import base
[<class 'sub.sub1.Sub1'>, <class 'sub.sub2.Sub2'>]
上面的输出完全符合我的预期。当我使用 Python 命令行运行 base.py 时,它变得很奇怪:
python3 base.py
[<class 'sub.sub2.Sub2'>]
[]
现在我认为我理解在第二种情况下有两个打印,因为 Python 导入器最初在 sys.modules 全局变量中没有看到 base.py,所以当导入子类时它将再次导入 base.py并且代码将被第二次执行。这个解释没有解释为什么它第一次打印[<class 'sub.sub2.Sub2'>]而不是[<class 'sub.sub1.Sub1'>],因为sub.sub1.Sub1是首先导入的,也没有解释为什么__subclasses__()中只有sub.sub2.Sub2出现,而sub.sub1.Sub1没有。
任何有助于我理解 Python 在这方面如何工作的解释都将不胜感激!
编辑:我想使用python base.py 运行模块,所以也许我可以指出正确的方向?
【问题讨论】:
-
简短回答:不要使用循环导入,也不要将同一文件视为脚本和可导入模块。当你做这些事情时,就会发生这种疯狂。此外,
__subclasses__也不是很有用,因为它只知道实际执行的子类定义。 -
谢谢,但我想了解这种行为。这不是生产就绪代码。总的来说,我知道并同意你所说的,但我要求对 Python 的内部有更深入的了解。
-
你有替代
__subclasses__()的替代方案,它在执行之前知道我的子类吗? -
静态代码分析工具可以帮助解决这个问题。
标签: python inheritance python-import