源題目與答案地址以下http://stackoverflow.com/questions/14132...。下面是個人翻譯(看做機翻也行),以及原文。python
這個問題是如何解決在相對導入的時候,若是出現'System Error'的時候的解決方案。順帶一提,這個問題好像出在源碼上,在issue 18018獲得解決,附上這個聽說能夠解決問題的地址:解決方案。我不知道怎麼使用,但願知道的讀者(若是有的話)能夠告訴我~shell
這裏是解釋。長話短說,這是由於在運行一個Python文件和從什麼地方導入那個文件之間,存在一個巨大的差別。你只要明白:一個文件到底在哪裏並不能決定Python以爲它在哪一個包裏面。此外,這實際上取決於你是如何將這個文件導入到Python中的。session
導入一個Python文件有兩種方法:做爲頂層文件,或者做爲一個模塊。若是你直接運行它,這個文件就會被看成頂層文件來執行,好比在命令行中輸入python myfile.py
。若是你使用python -m myfile
,或者它是經過其餘文件的import
語句導入的,那這個文件就會做爲一個模塊被導入。一次只能有一個頂層文件;頂層文件是你一開始運行的Python文件。app
當一個文件被導入的時候,它會獲得一個名字(存儲在其__name__
屬性中)。若是它是做爲頂層文件被導入的,那麼它的__name__
就是__main__
;若是它是做爲一個模塊被導入的,則它的__name__
就是它的文件名,先於任何它所組成的包或子包,由點號分開。less
因此,看看你這裏的例子ide
package/ __init__.py subpackage1/ __init__.py moduleX.py moduleA.py enter code here
若是你導入moduleX(注意,導入而非運行),那麼它的名字就是package.subpackage1.moduleX
。若是你導入moduleA
,則它的名字就是package.moduleA
。但是,若是你直接從命令行運行moduleX
,則它的名字就會被__main__
取而代之,moduleA
也是如此。當一個模塊做爲頂層文件被運行的時候,其會失去自己的名字,並由__main__
取而代之。函數
這裏有一個附送的小技巧:模塊名取決於它是從所在的目錄直接導入,或者經過一個包導入的。這隻有在你從目錄中運行Python,以及嘗試在相同的目錄(或者它的子目錄)導入一個文件的時候有差異。舉個例子,若是你在目錄package/subpackage1
運行Python解釋器,而後導入moduleX
,moduleX的名字就只會是moduleX
,而不是package.subpackage1.moduleX
。這是由於,Python將當前的路徑添加到模塊搜索路徑的開頭;若是它發現當前目錄有一個須要運行的模塊,它不會明白這個目錄是包的一部分,而這個包的信息也不會成爲模塊名的一部分。this
若是你只是交互式地運行解釋器,會出現一個特殊狀況(好比:輸入python
並進入shell)。這種狀況下,這個交互式會話的名字是__main__
。spa
你的錯誤其實是:若是一個模塊名沒有點,它不會被視做包的一部分。這個文件實際上在哪一個目錄可有可無。惟一相關的是,它的名字是什麼,而它的名字取決於你是如何導入它的。命令行
如今,看看你在問題中所引用的內容:
相對導入使用一個模塊的
__name__
屬性來決定模塊在包中的層次。若是模塊的名字不包含任何模塊信息(好比被設置爲__main__
),那麼相對導入將會把該模塊視做頂層模塊,忽視其在文件系統中的實際位置。
相對導入使用模塊的__name__
決定它是否在一個包內。當你是用相似form .. import foo
進行相對導入的時候,點代表在包的層次中上升多少。舉個例子,若是你當前的模塊的名字是package.subpackage1.moduleX
,那麼..moduleA
就表示模塊package.moduleA
。要想讓from .. import
語句起做用,模塊的名字至少有在import
語句中的點的數量。
可仍是,若是你的模塊名是__main__
,那麼它不會被看成一個包。它的名字裏面沒有點,所以你不能在文件內使用from .. import
語句。若是你嘗試這麼幹,你會得到錯誤relative-import in non-package
。
你想作的事情大概是嘗試要從命令行中運行moduleX。當你這麼幹的時候,它的名字會被設置爲__main__
,這意味着裏面的相對導入失效了,由於:它的名字並無顯示出它在一個包裏面。注意,這會發生在你從相同的目錄運行中運行Python並試圖導入那個模塊的時候,這是由於:如上所說,python會在乎識到這是包的一部分以前,在當前目錄下「過早」找到那個模塊。
你也要記得,當你運行一個交互式解釋器的時候,交互式會話的name
老是__main__
。因此,你不能在交互式會話中直接使用任何相對導入。相對導入只能使用在模塊文件內。
兩個解決方案:
若是你真的向直接運行moduleX,但你但願它能夠被視做包的一部分,那使用python -m package.subpackage.moduleX
運行便可。選項-m
告訴Python將其做爲一個模塊而非頂層文件導入。
若是你不不但願真的運行moduleX,你只想運行其餘使用了在moduleX
裏的函數的腳本,如myfile.py
。在這種嗯狀況下,將myfile.py
放到其餘地方——不在包目錄裏面——並運行它。若是在myfile.py
裏面,你作點相似從package.moduleA
裏面導入spam
,它會作的很好~
注意事項:
對於這兩個解決方法的任意一個來講,包目錄必須在模塊搜索路徑
sys.path
中。若是不是的話,你不能確實可靠地使用包裏面的任何東西。
自從Python2.6以來,包依賴的解決不只僅取決於模塊的名字,還有模塊的__package
屬性。這使我爲何避免使用__name__
來指代模塊的名字。一個模塊的名字如今多是__package__ + __name__
了,除非沒有包。
原文以下:
Script vs. Module
Here's an explanation. The short version is that there is a big difference between directly running a Python file, and importing that file from somewhere else. Just knowing what directory a file is in does not determine what package Python thinks it is in. That depends, additionally, on how you load the file into Python (by running or by importing).
There are two ways to load a Python file: as the top-level script, or as a module. A file is loaded as the top-level script if you execute it directly, for instance by typing python myfile.py on the command line. It is loaded as a module if you do python -m myfile, or if it is loaded when an import statement is encounted inside some other file. There can only be one top-level script at a time; the top-level script is the Python file you ran to start things off.
Naming
When a file is loaded, it is given a name (which is stored in its name attribute). If it was loaded as the top-level script, its name is __main__. If it was loaded as a module, its name is the filename, preceded by the names of any packages/subpackages of which it is a part, separated by dots.
So for instance in your example:
package/
__init__.py subpackage1/ __init__.py moduleX.py moduleA.py
enter code here
if you imported moduleX (note: imported, not directly executed), its name would be package.subpackage1.moduleX. If you imported moduleA, its name would be package.moduleA. However, if you directly run moduleX from the command line, its name will instead be __main__, and if you directly run moduleA from the command line, its name will be __main__. When a module is run as the top-level script, it loses its normal name and its name is instead __main__.
Accessing a module NOT through its containing package
There is an additional wrinkle: the module's name depends on whether it was imported "directly" from the directory it is in, or imported via a package. This only makes a difference if you run Python in a directory, and try to import a file in that same directory (or a subdirectory of it). For instance, if you start the Python interpreter in the directory package/subpackage1 and then do import moduleX, the name of moduleX will just be moduleX, and not package.subpackage1.moduleX. This is because Python adds the current directory to its search path on startup; if it finds the to-be-imported module in the current directory, it will not know that that directory is part of a package, and the package information will not become part of the module's name.
A special case is if you run the interpreter interactively (e.g., just type python and start entering Python code on the fly). In this case the name of that interactive session is __main__.
Now here is the crucial thing for your error message: if a module's name has no dots, it is not considered to be part of a package. It doesn't matter where the file actually is on disk. All that matters is what its name is, and its name depends on how you loaded it.
Now look at the quote you included in your question:
Relative imports use a module's name attribute to determine that module's position in the package hierarchy. If the module's name does not contain any package information (e.g. it is set to 'main') then relative imports are resolved as if the module were a top level module, regardless of where the module is actually located on the file system.
Relative imports...
Relative imports use the module's name to determine where it is in a package. When you use a relative import like from .. import foo, the dots indicate to step up some number of levels in the package hierarchy. For instance, if your current module's name is package.subpackage1.moduleX, then ..moduleA would mean package.moduleA. For a from .. import to work, the module's name must have at least as many dots as there are in the import statement.
... are only relative in a package
However, if your module's name is __main__, it is not considered to be in a package. Its name has no dots, and therefore you cannot use from .. import statements inside it. If you try to do so, you will get the "relative-import in non-package" error.
Scripts can't import relative
What you probably did is you tried to run moduleX or the like from the command line. When you did this, its name was set to __main__, which means that relative imports within it will fail, because its name does not reveal that it is in a package. Note that this will also happen if you run Python from the same directory where a module is, and then try to import that module, because, as described above, Python will find the module in the current directory "too early" without realizing it is part of a package.
Also remember that when you run the interactive interpreter, the "name" of that interactive session is always __main__. Thus you cannot do relative imports directly from an interactive session. Relative imports are only for use within module files.
Two solutions:
If you really do want to run moduleX directly, but you still want it to be considered part of a package, you can do python -m package.subpackage.moduleX. The -m tells Python to load it a s a module, not as the top-level script. Or perhaps you don't actually want to run moduleX, you just want to run some other script, say myfile.py, that uses functions inside moduleX. If that is the case, put myfile.py somewhere else --- not inside the package directory -- and run it. If inside myfile.py you do things like from package.moduleA import spam, it will work fine.
Notes
For either of these solutions, the package directory (package in your example) must be accessible from the Python module search path (sys.path). If it is not, you will not be able to use anything in the package reliably at all. since Python 2.6, the module's "name" for package-resolution purposes is determined not just by its __name__ attributes but also by the __package__ attribute. That's why I'm avoiding using the explicit symbol __name__ to refer to the module's "name". Since Python 2.6 a module's "name" is effectively __package__ + '.' + __name__, or just __name__ if __package__ is None.)