Python类工厂问题引用基类?
我最近看到一个关于Python类工厂实现的内容,觉得它非常适合我正在处理的问题。唯一不同的是,我想把基类和子类放在不同的包里。
但是,当我尝试这样做时,每当我想加载基类时,就会遇到问题。
结构如下:
BaseClass.py
from subclasses import *
def NewClass():
"""Map Factory"""
for cls in BaseClass.__subclasses__():
print "checking class..."
class BaseClass(object):
def __init__(self):
print("Building an abstract BaseMap class..")
subclasses/__init__.py
__all__=['SubClass']
subclasses/SubClass.py
from BaseClass import BaseClass
class SubClassA(BaseClass):
def __init__(self):
print('Instantiating SubClassA')
当我尝试导入BaseClass时,却出现了以下错误:
1 #import BaseClass ----> 2 from BaseClass import BaseClass 3 class SubClassA(BaseClass): 4 def __init__(self): 5 print('Instantiating SubClassA') ImportError: cannot import name BaseClass
我还尝试过使用“import BaseClass”,然后再去继承“BaseClass.BaseClass”,但这又导致了另一个错误:
1 import BaseClass ----> 2 class SubClassA(BaseClass.BaseClass): 3 def __init__(self): 4 print('Instantiating SubClassA') AttributeError: 'module' object has no attribute 'BaseClass'
最后,如果我只是尝试创建子类目录,那是没有问题的。只有在我尝试导入BaseClass模块时,事情才会出错。
有没有什么想法?
2 个回答
根据你提供的信息,看来你的模块 BaseClass
可能没有直接放在 Python 的搜索路径上。虽然 BaseClass 能找到它下面的子类,因为这些子类在 BaseClass 的下方目录中,但反过来就不行了。
使用一个相对导入可以解决这个问题。
from .. BaseClass import BaseClass
这里的 ..
是用来向上移动一个目录,就像文件路径那样。另一种方法是把 BaseClass 直接放在 PYTHONPATH 中。
不过,老实说,让两个不同的模块互相依赖听起来并不是个好主意。更好的做法是让子类去注册给 BaseClass。
编辑:
我所说的“注册给基类”是指类似下面这样的做法:
# baseclass.py
subclasses = []
def register(cls):
subclasses.append(cls)
# subclass.py
class SubClassA(BaseClass):
...
baseclass.register(SubClassA)
这样一来,BaseClass 就不需要知道所有不同的子类了。子类可以注册自己被使用,BaseClass 在使用它们时也不需要事先了解它们。
一些实验表明,问题出在导入的递归上。在BaseClass.py文件中把导入语句做成条件性的,解决了我测试中的问题:
if __name__ == '__main__':
from subclasses import *
这样可以避免递归,Python似乎对此很满意。
[编辑]
一个更好的解决方案是把NewClass的方法放在一个单独的文件里:
something.py
from BaseClass import BaseClass
from subclasses import *
def NewClass():
"""Map Factory"""
for cls in BaseClass.__subclasses__():
print ("checking class...")
NewClass ()