![](/img/trans.png)
[英]ImportError: cannot import name 'nsprefixes' Python 3.5
[英]Python 3.5 "ImportError: cannot import name 'SomeName'
我正在嘗試為Python 3.5實現一個小型庫,但一直在努力如何正確處理包/模塊的結構以及如何使導入工作。
我一直遇到python抱怨無法導入某些名稱的錯誤,例如
ImportError: cannot import name 'SubClass1'
當“ SubClass1”需要導入其他模塊但該其他模塊也需要了解SubClass1(循環導入)時,似乎會發生這種情況。 我需要在庫中進行循環導入,因為基類具有創建適當子類實例的工廠方法(在其他情況下,也需要循環導入,例如,檢查函數參數的類型時,需要導入該類型所在的位置定義,但是該模塊本身可能需要完成檢查的類:另一個循環依賴項!)
這是示例代碼:
根目錄包含子目錄dir1。 目錄dir1包含一個空文件init .py,一個文件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),因為“ import。subclass1”或類似方法不起作用。
您的問題是由循環導入引起的。 baseclass
模塊正嘗試從subclass1
模塊導入SubClass1
,但是subclass
正嘗試向后導入BaseClass
。 您會收到NameError
因為在運行import
語句NameError
未定義類。
有幾種方法可以解決此問題。
一種選擇是更改導入樣式。 無需按名稱導入類,只需導入模塊並稍后將名稱作為屬性查找。
from . import baseclass
class SubClass1(baseclass.BaseClass):
pass
和:
from . import subclass1
class BaseClass:
def make(self,somearg):
# ...
ret = subclass1.SubClass1()
因為SubClass1
需要能夠在定義時立即使用BaseClass
,所以如果在subclass1
之前導入baseclass
模塊,則此代碼可能仍然會失敗。 所以不理想
另一種選擇是更改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
繼承的類)。 如果僅處理實際的繼承子類,則可能要考慮使用一個元類,該元類會自動為您完成所有子類的注冊。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.