从基类导入子类在Python中

7 投票
3 回答
16768 浏览
提问于 2025-04-17 07:22

我有一个基础类,这个类里面有一个方法,可以根据输入的字符串创建一个子类的实例,子类的名字和输入的字符串是一样的。

之前我把基础类和子类都放在同一个文件里,这样就可以用 globals()[name] 这种方式来实现。

不过现在我把子类分到其他文件里了。每个子类文件的顶部都有一个 import base 的语句,所以我不能直接在基础类里导入这些子类,否则就会出现循环导入的问题。

有没有什么解决办法呢?

base.py 文件里:

from basefactory import BaseFactory
class Base:
    def __init__(self, arg1, arg2):
        ...
    def resolve(self, element):
        className = typing.getClassName(element)
        return BaseFactory.getInstance(className, element, self)

basefactory.py 文件里:

from file1 import *
from file2 import *
...
class BaseFactory:
    @staticmethod
    def getInstance(name, arg1, arg2):
       subclass = globals()[name]
       return subclass(arg1, arg2)

file1.py 文件里:

from base import Base

class subclass1(Base):
    def foo(self):
        return self.arg1

3 个回答

0

我不太明白你的意思,为什么你要把子类从主类里拿出来,如果你还需要它们在里面呢?那就把它们放在主类里面,等你需要的时候,可以用 from class import subclass 来导入。

7

根据我的理解,你有:

  1. 一个基础类
  2. 从基础类派生出的一系列子类
  3. 基础类里有一个工厂方法,用来实例化正确类型的子类
  4. 这些子类被分成了不同的文件,并且它们依赖于基础类,但基础类里的工厂方法又依赖于这些子类

一个解决办法是创建一个单独的函数或类来实现工厂方法,并把它放在一个与基础类不同的文件中。这个文件可以导入基础类和子类的所有文件,这样就不会出现循环引用的问题。

举个例子:

# base.py:
class baseClass():
   def __init__(self):
      self.name = "Base"

# sub1.py:
from base import baseClass
class sub1Class(baseClass):
   def __init__(self):
      self.name = "sub1"

# sub2.py:
from base import baseClass
class sub2Class(baseClass):
   def __init__(self):
      self.name = "sub2"

# factory.py:
from sub1 import sub1Class
from sub2 import sub2Class # should not create an error
mapping = {'sub1': sub1Class, 'sub2': sub2Class}

def create(baseType):
  return mapping[baseType]

其实,更好的方法可能是使用 type

type(name, bases, dict) 会返回一个新的类型对象。这实际上是类声明的一种动态形式。name 字符串是类名,并成为 __name__ 属性;bases 元组列出了基础类,并成为 __bases__ 属性;而 dict 字典则是包含类体定义的命名空间,并成为 __dict__ 属性。例如,以下两个语句创建的类型对象是完全相同的:

>>> class X(object):
...     a = 1
...
>>> X = type('X', (object,), dict(a=1))

为什么不把 resolve 移到一个管理类里呢?可以看看 Python中的类工厂里的域类。我不确定是否需要 resolve……你可以直接通过 self.__class__.__name__ 获取类名,并使用像 type()isinstance() 这样的 Python 函数来检查它们是否是特定类型。

另外,看看这些链接:
你能用字符串来实例化一个类吗?
Python有没有类似于Java的Class.forName()?

7

你可以把出错的import语句移动到创建子类对象的方法里面。

撰写回答