__subclasses__() 和导入

问题描述 投票:0回答:1

有两个带有命令链的文件和一个动态收集所有非抽象命令的字典。

逻辑.py

from abc import ABC, abstractmethod

class Command(ABC):
    def __init__(self):
        ...
    
    @abstractmethod
    def run():
        ...

class Commands(dict):
    def __init__(self):
        import comm
        breakpoint()
        for cls in Command.__subclasses__():
            names = self.split_camel_case(cls.__name__)
            self[names] = cls

comm.py

from logic import Command

class TestCommand(Command):
    ...

调试器输出

> logic.py(28) __init__()
  -> for cls in Command.__subclasses__():

(Pdb) comm.TestCommand.__mro__
(<class 'comm.TestCommand'>, <class 'logic.Command'>, <class 'abc.ABC'>, <class 'object'>)

(Pdb) Command.__subclasses__()
[]

Commands.__init__()
被称为基类
Command
时,已经定义了。模块
comm
被导入,子类
TestCommand
也被定义。但是
Command.__subclass__()
返回的列表是空的。

请告诉我,我错过了什么?

python python-import
1个回答
0
投票

我认为问题在于,令人困惑的是,您从

Command
内部看到的
Commands.__init__
类对象与
TestCommand
继承自的对象不同。

在某种程度上,是的,它们是相同的,但对于 Python 导入系统来说,它们是不同的。

尝试这段代码,看看会发生什么:

logic.py

from abc import ABC, abstractmethod

class Command(ABC):
    def __init__(self):
        ...
    
    @abstractmethod
    def run():
        ...

class Commands(dict):
    def __init__(self):
        import comm
        print(Command.__module__)
        print(Command.__subclasses__())


if __name__ == "__main__":
    Commands()

comm.py

from logic import Command

class TestCommand(Command):
    ...


if __name__ == "__main__":
    print(Command.__module__)
    print(Command.__subclasses__())
$ python comm.py
logic
[<class '__main__.TestCommand'>]

$ python logic.py
__main__
[]

请注意两个

Command
类引用如何具有不同的
__module__
值。

Commands.__init__
具有对其所属模块完全定义之前定义的
Command
类的引用。

我们可以通过将逻辑移至第三个文件来解决此问题:

base.py

from abc import ABC, abstractmethod

class Command(ABC):
    def __init__(self):
        ...
    
    @abstractmethod
    def run():
        ...

comm.py

from base import Command

class TestCommand(Command):
    ...

logic.py

from base import Command
import comm

class Commands(dict):
    def __init__(self):
        print(Command.__module__)
        print(Command.__subclasses__())


if __name__ == "__main__":
    Commands()

现在,当我们运行它时,我们得到了想要的结果:

$ python logic.py
base
[<class 'comm.TestCommand'>]
© www.soinside.com 2019 - 2024. All rights reserved.