Python 3.5 "ImportError: 无法导入名称 'SomeName'



我正在尝试为python 3.5实现一个小库,但是一直在努力正确处理包装/模块的结构以及如何使导入工作的工作。

我一直遇到python抱怨无法以错误导入某些名称的问题,例如

ImportError: cannot import name 'SubClass1'

当" subclass1"需要导入其他模块时,这似乎会发生,但是其他模块还需要了解subclass1(循环导入)。我需要在库中进行周期导入,因为基类具有一种工厂方法,可以创建适当的子类实例(在其他情况下需要循环导入,例如检查函数参数的类型需要该类型的导入到何处定义,但是该模块本身可能需要进行检查的地方:另一个环状依赖性!)

这是示例代码:

根目录包含子目录DIR1。目录dir1包含和空文件 init .py,file baseclass.py和文件subclass1.py。文件./dir1/subclass1.py包含:

from . baseclass import BaseClass
class SubClass1(BaseClass):
   pass

文件./dir1/baseclass.py包含:

from . subclass1 import SubClass1
class BaseClass(object):
   def make(self,somearg):
      # .. some logic to decide which subclass to create
      ret = SubClass1()
      # .. which gets eventually returned by this factory method
      return ret

文件./test1.py包含:

from dir1.subclass1 import SubClass1
sc1 = SubClass1()

这会导致以下错误:

Traceback (most recent call last):
  File "test1.py", line 1, in <module>
     from dir1.subclass1 import SubClass1
  File "/data/johann/tmp/python1/dir1/subclass1.py", line 1, in <module>
    from . baseclass import BaseClass
  File "/data/johann/tmp/python1/dir1/baseclass.py", line 1, in <module>
    from . subclass1 import SubClass1
ImportError: cannot import name 'SubClass1'

解决此问题的标准/最佳方法是什么,理想情况下,以python 2.x和Python 3兼容3.2版的方式是向后兼容的方式?

我在其他地方读到,导入模块而不是从模块中的东西可能会有所帮助,但我不知道如何以相对方式导入模块(例如subclass1),因为"导入。。

您的问题是由循环导入引起的。baseclass模块正在尝试从subclass1模块导入SubClass1,但是subclass试图直接导入BaseClass。您会得到NameError,因为import语句正在运行时尚未定义类。

有几种解决问题的方法。

一种选择是改变您的导入风格。而不是按名称导入类,只需导入模块,然后查找名称,如以后的属性。

from . import baseclass
class SubClass1(baseclass.BaseClass):
    pass

和:

from . import subclass1
class BaseClass:
    def make(self,somearg):
        # ...
        ret = subclass1.SubClass1()

因为SubClass1需要在定义时立即使用BaseClass,因此如果baseclass模块在subclass1之前导入,则此代码仍可能会失败。所以这不是理想的

另一个选项是更改baseclass以在BaseClass的定义下进行导入。这样,subclass模块将在需要时导入:

class BaseClass:
    def make(self,somearg):
        # .. some logic to decide which subclass to create
        ret = SubClass1()
from .subclass1 import SubClass1

这不是理想的选择,因为放置进口的普通位置位于文件的顶部。将它们放在其他地方使代码更令人困惑。您可能需要在文件的顶部发表评论,以解释为什么您要延迟此路线时延迟导入。

另一个选项可能是将两个模块组合到一个文件中。Python不需要每个班级都有自己的模块,就像其他语言一样。当您紧密耦合的课程(例如示例中的课程)时,将它们全部放在一个地方很有意义。这使您可以避免整个问题,因为您根本不需要任何进口。

最后,还有一些更复杂的解决方案,例如依赖注入。每个子类都可以通过调用一些功能并传递对自身的引用,而不是基本类需要了解子类的基础类。例如:

# no imports of subclasses!
def BaseClass:
    subclasses = []
    def make(self, somearg):
        for sub in self.subclasses:
            if sub.accepts(somearg):
                return sub()
        raise ValueError("no subclass accepts value {!r}".format(somearg))
    @classmethod
    def register(cls, sub):
        cls.subclasses.append(sub)
        return sub        # return the class so it can be used as a decorator!

subclass.py

from .baseclass import BaseClass
@BaseClass.register
class SubClass1(BaseClass):
    @classmethod
    def accepts(cls, somearg):
        # put logic for picking this subclass here!
        return True

这种编程样式更为复杂,但是它可以很好地扩展,因为它比BaseClass需要在前面了解所有子类的版本更容易扩展。使用register功能只是其中之一,您可以通过多种方式实现这种代码。它的一件好事是,它不严格需要继承(因此您可以注册一个实际上不会从BaseClass继承的类)。如果您仅处理实际继承子类,则可能需要考虑使用自动为您的所有子类注册的元素。

最新更新